diff --git a/src/test/java/com/example/dm/config/SecurityConfigTest.java b/src/test/java/com/example/dm/config/SecurityConfigTest.java new file mode 100644 index 0000000..bc669c0 --- /dev/null +++ b/src/test/java/com/example/dm/config/SecurityConfigTest.java @@ -0,0 +1,25 @@ +package com.example.dm.config; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("SecurityConfig 테스트") +class SecurityConfigTest { + @Autowired + private SecurityConfig securityConfig; + + @Test + @DisplayName("비밀번호 암호화가 잘 되는지 확인하기") + void passwordEncoder() { + String testSentence = "비밀번호 암호화 테스트"; + String encodedSentence = securityConfig.passwordEncoder().encode(testSentence); + assertTrue(securityConfig.passwordEncoder().matches(testSentence, encodedSentence)); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/dm/controller/AuthControllerTest.java b/src/test/java/com/example/dm/controller/AuthControllerTest.java new file mode 100644 index 0000000..fc81d39 --- /dev/null +++ b/src/test/java/com/example/dm/controller/AuthControllerTest.java @@ -0,0 +1,142 @@ +package com.example.dm.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.example.dm.dto.users.LoginDto; +import com.example.dm.dto.users.SignupDto; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("AuthController 테스트") +class AuthControllerTest { + @Resource + MockMvc mockMvc; + @Resource + ObjectMapper objectMapper; + + @Autowired + PasswordEncoder passwordEncoder; + + @Value("${jwt.access.header}") + private String ACCESS_HEADER; + + @Value("${jwt.refresh.header}") + private String REFRESH_HEADER; + + // 테스트를 위한 공용 변수 + String email = "devmingle11@gmail.com"; + String nickname = "nickname"; + String password = "Passord1234#"; + + + + @Test + @DisplayName("이메일 인증발급 확인") + void sendOtp() { + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/otp") + .param("email", email) + .contentType(MediaType.APPLICATION_JSON) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(email)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("닉네임 중복체크 테스트") + void checkNickname(){ + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/nickname") + .param("nickname", nickname) + .contentType(MediaType.APPLICATION_JSON) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(nickname)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @Rollback(false) + @DisplayName("회원가입 테스트") + void signup() { + SignupDto dto = getSignupDto(); + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.createdAt").isNotEmpty()) + .andExpect(jsonPath("$.data.email").value(email)) + .andExpect(jsonPath("$.data.userProfile.nickname").value(nickname)) + .andExpect(header().exists(ACCESS_HEADER)) + .andExpect(header().exists(REFRESH_HEADER)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("로그인 테스트") + void login() { + LoginDto dto = new LoginDto(email, password); + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/login") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(email)) + .andExpect(header().exists(ACCESS_HEADER)) + .andExpect(header().exists(REFRESH_HEADER)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + + private SignupDto getSignupDto() { + return SignupDto.builder() + .email(email) + .password(password) + .nickname(nickname) + .city("city") + .state("state") + .street("street") + .build(); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/dm/controller/UserControllerTest.java b/src/test/java/com/example/dm/controller/UserControllerTest.java new file mode 100644 index 0000000..d75b5f0 --- /dev/null +++ b/src/test/java/com/example/dm/controller/UserControllerTest.java @@ -0,0 +1,210 @@ +package com.example.dm.controller; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.example.dm.dto.users.ChangePwdDto; +import com.example.dm.dto.users.MypageDto; +import com.example.dm.dto.users.SignupDto; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import java.util.HashMap; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("UserController 테스트") +class UserControllerTest { + @Resource + MockMvc mockMvc; + @Resource + ObjectMapper objectMapper; + + @Autowired + PasswordEncoder passwordEncoder; + + @Value("${jwt.access.header}") + private String ACCESS_HEADER; + + @Value("${jwt.refresh.header}") + private String REFRESH_HEADER; + + // 테스트를 위한 공용 변수 + String email = "devmingle@gmail.com"; + String nickname = "nickname"; + String changedNickname = "changedNickname"; + String password = "Passord1234#"; + String accessToken, refreshToken; + + + @BeforeEach + @DisplayName("먼저 회원가입 실행 후 토큰 가져오기") + void setUp() throws Exception { + SignupDto dto = getSignupDto(); + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + + // 토큰 추출 + accessToken = "Bearer " + resultActions.andReturn().getResponse().getHeader(ACCESS_HEADER); + refreshToken = "Bearer " + resultActions.andReturn().getResponse().getHeader(REFRESH_HEADER); + } + + @Test + @DisplayName("회원정보 조회 테스트") + void getProfiles() { + try { + ResultActions resultActions = mockMvc.perform( + get("/api/v1/users/profile") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.email").value(email)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("회원정보 수정 테스트") + void editProfiles() { + MypageDto dto = getMypageDto(); + try { + ResultActions resultActions = mockMvc.perform( + put("/api/v1/users/profile") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.email").value(email)) + .andExpect(jsonPath("$.data.userProfile.nickname").value(changedNickname)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("비밀번호 초기화 테스트") + void resetPassword() { + Map map = new HashMap<>(); + map.put("password",password); + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/password/reset") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(map)) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(email)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("비밀번호 변경 테스트") + void changePassword() { + try { + ChangePwdDto dto = new ChangePwdDto(password, "password1234##"); + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/password/change") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(true)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("랜덤 비밀번호 전송 테스트") + void isRandomPassword() { + try { + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users/password/reset/confirm") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data.email").value(email)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + @DisplayName("회원탈퇴 테스트") + void deleteUser() { + try { + ResultActions resultActions = mockMvc.perform( + delete("/api/v1/users") + .header(ACCESS_HEADER, accessToken) + .header(REFRESH_HEADER, refreshToken) + ); + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.data").value(email)) + .andDo(print()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private MypageDto getMypageDto() { + return MypageDto.builder() + .id(1L) + .nickname(changedNickname) + .city("city") + .state("state") + .street("street") + .build(); + } + + private SignupDto getSignupDto() { + return SignupDto.builder() + .email(email) + .password(password) + .nickname(nickname) + .city("city") + .state("state") + .street("street") + .build(); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/dm/security/jwt/TokenFilterTest.java b/src/test/java/com/example/dm/security/jwt/TokenFilterTest.java new file mode 100644 index 0000000..4a1c564 --- /dev/null +++ b/src/test/java/com/example/dm/security/jwt/TokenFilterTest.java @@ -0,0 +1,83 @@ +package com.example.dm.security.jwt; + +import static org.mockito.Mockito.mock; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.example.dm.dto.users.SignupDto; +import com.example.dm.entity.LoginUser; +import com.fasterxml.jackson.databind.ObjectMapper; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +@SpringBootTest +@AutoConfigureMockMvc +@DisplayName("토큰 필터 테스트") +public class TokenFilterTest { + @Resource + MockMvc mockMvc; + @Resource + ObjectMapper objectMapper; + + @Autowired + TokenFilter tokenFilter; + + TokenProvider tokenProvider; + private String token; + + @BeforeEach + public void setUp() { + tokenProvider = mock(TokenProvider.class); + token = tokenProvider.generateAccessToken(mock(LoginUser.class)); + } + + @Test + @DisplayName("토큰 검증이 필요하지 않은 엔드포인트") + public void doFilterTestWithToken() throws Exception { + mockMvc.perform(get("/actuator/health")) + .andExpect(status().isOk()) + .andDo(print()); + } + + @Test + @DisplayName("토큰 검증이 필요한 엔드포인트") + public void doFilterTestWithoutToken() throws Exception { + SignupDto dto = makeSignDto(); + + ResultActions resultActions = mockMvc.perform( + post("/api/v1/users") + .header("Authorization", "Bearer " + token) + .header("Authorization-refresh", "Bearer " + token) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto)) + ); + + resultActions + .andExpect(status().isOk()) + .andExpect(jsonPath("$.status").value(200)) + .andExpect(jsonPath("$.data.createdAt").isNotEmpty()) + .andDo(print()); + } + + // 유효성 필요로 테스트용 객체 생성 + private SignupDto makeSignDto() { + return new SignupDto("devmingle11@gmail.com","Password11#", + "nickname", + "City", "State", "Street", + 52.65165, 65.8451321, + "introduce", + "localhost:8080","localhost", + "email",""); + } +} diff --git a/src/test/java/com/example/dm/security/jwt/TokenProviderTest.java b/src/test/java/com/example/dm/security/jwt/TokenProviderTest.java new file mode 100644 index 0000000..681a58a --- /dev/null +++ b/src/test/java/com/example/dm/security/jwt/TokenProviderTest.java @@ -0,0 +1,134 @@ +package com.example.dm.security.jwt; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.verify; + +import com.example.dm.entity.LoginUser; +import io.jsonwebtoken.JwtParser; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.UnsupportedJwtException; +import jakarta.servlet.http.HttpServletResponse; +import java.security.Key; +import java.util.Map; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@DisplayName("TokenProvider 메서드 테스트") +class TokenProviderTest { + @Autowired + private TokenProvider tokenProvider; + + @Value("${jwt.access.header}") + private String accessHeader; + @Value("${jwt.refresh.header}") + private String refreshHeader; + + @Mock + private HttpServletResponse response; + @Mock + private Jwts jwts; + @Mock + private Key key; + + Map map; + + private LoginUser loginUser; + private final Long ID = 1L; + private final Long USERPROFILES_ID = 1L; + private final String EMAIL = "token@test.com"; + private final String PASSWORD = "password"; + private final String ROLE = "USER"; + private final String NICKNAME = "nickname"; + + @BeforeEach + void setUp(){ + loginUser = LoginUser.create(ID, USERPROFILES_ID,EMAIL, PASSWORD, ROLE, NICKNAME); + } + + @Test + @DisplayName("토큰 생성시 User 정보가 들어가는지 확인") + void generateToken() { + // LoginUser 정보로 생성하는 token + String accessTokenByUser = tokenProvider.generateAccessToken(loginUser); + String refreshTokenByUser = tokenProvider.generateRefreshToken(loginUser); + assertEquals(EMAIL, tokenProvider.extractUsername(accessTokenByUser)); + assertEquals(EMAIL, tokenProvider.extractUsername(refreshTokenByUser)); + + // token 정보로 생성하는 token + String newAccessToken = tokenProvider.generateAccessToken(accessTokenByUser); + String newRefreshToken = tokenProvider.generateRefreshToken(refreshTokenByUser); + assertEquals( + tokenProvider.getExtraClaims(newAccessToken).get("password"), + tokenProvider.getExtraClaims(loginUser).get("password") + ); + + assertEquals( + tokenProvider.getExtraClaims(newRefreshToken).get("password"), + tokenProvider.getExtraClaims(loginUser).get("password") + ); + } + + @Test + @DisplayName("claims 추출 확인") + void extraClaims() { + String token = tokenProvider.generateAccessToken(loginUser); + map = tokenProvider.getExtraClaims(token); + assertEquals(ID, Long.valueOf((Integer) map.get("id"))); + assertEquals(PASSWORD, map.get("password")); + assertEquals("ROLE_" + ROLE, map.get("role")); + assertEquals(NICKNAME, map.get("nickname")); + assertEquals(EMAIL, tokenProvider.extractUsername(token)); + } + + @Test + @DisplayName("response에 인증정보 넣기") + void setAuthenticationTokens() { + String accessToken = tokenProvider.generateAccessToken(loginUser); + String refreshToken = tokenProvider.generateRefreshToken(loginUser); + tokenProvider.setAuthenticationTokens(response, accessToken, refreshToken); + verify(response).setHeader(accessHeader, accessToken); + verify(response).setHeader(refreshHeader, refreshToken); + } + + @Nested + @DisplayName("토큰 유효성 테스트") + class validateToken { + JwtParser jwtParser = jwts.parserBuilder().setSigningKey(key).build(); + + @Test + @DisplayName("유효한 토큰 여부") + void validToken(){ + String token = tokenProvider.generateAccessToken(loginUser); + assertTrue(tokenProvider.validateToken(token)); + } + + @Test + @DisplayName("유효하지 않은 토큰 여부") + void invalidToken(){ + assertThrows(IllegalArgumentException.class, () -> jwtParser.parseClaimsJws("")); + } + + @Test + @DisplayName("지원하지 않는 토큰 여부") + void unsupportedToken(){ + String unsupportedToken = "eyJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IntiY3J5cHR9JDJhJDEwJFJDbE1pVDlUS2NsNmRHN2ZxT2tJdHVCdzNqemJKYzZNQkgwWkV5bExTRFdLcGxkN3FGWlg2Iiwicm9sZSI6IlJPTEVfVVNFUiIsIm5pY2tuYW1lIjoibmlja25hbWUiLCJpZCI6MSwic3ViIjoiZW1haWxAZG9tYWluLmNvbSIsImlhdCI6MTY5NTk4NTI1MSwiZXhwIjoxNjk1OTg1NTUxfQ.Lh9rSa6O_oW__FThK6iwPPFUNKNW5S60_mEYqGdvI7A"; + assertThrows(UnsupportedJwtException.class, () -> jwtParser.parseClaimsJws(unsupportedToken)); + } + +// @Test +// @DisplayName("만료된 토큰 여부") +// void expiredToken(){ +// String expiredToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMiwiZXhwIjoxNTE2MjM5MDIzfQ.4r7wFehZ2HeVSULgOCTzzH7Qaru2TndAh-TDJ2YXJts"; +// assertThrows(ExpiredJwtException.class, () -> jwtParser.parseClaimsJws(expiredToken)); +// } + } +} \ No newline at end of file diff --git a/src/test/java/com/example/dm/util/MailSenderTest.java b/src/test/java/com/example/dm/util/MailSenderTest.java new file mode 100644 index 0000000..6878567 --- /dev/null +++ b/src/test/java/com/example/dm/util/MailSenderTest.java @@ -0,0 +1,43 @@ +package com.example.dm.util; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +import jakarta.mail.MessagingException; +import jakarta.mail.SendFailedException; +import java.io.UnsupportedEncodingException; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@DisplayName("메일 전송 테스트") +class MailSenderTest { + @Autowired + MailSender mailSender; + + private final String EMAIL = "devmingle11@gamil.com"; + + // fromEmail 설정 + // application-auth -> mail.email + + /* 실제 메일 전송됨으로 주의 */ + @Test + @DisplayName("이메일 인증 메일링 테스트") + void sendEmailVerification() throws MessagingException, UnsupportedEncodingException { + mailSender.sendEmailVerification(EMAIL); + } + + /* 실제 메일 전송됨으로 주의 */ + @Test + @DisplayName("랜덤 비밀번호 발송 테스트") + void sendRandomPwd() throws MessagingException, UnsupportedEncodingException { + mailSender.sendRandomPwd(EMAIL,"random_password"); + } + + @Test + @DisplayName("이메일 형식이 올바르지 않은 경우") + void exceptionTest() { + assertThrows(SendFailedException.class, () -> mailSender.sendMail(EMAIL, "subject", "contents")); + } +} \ No newline at end of file diff --git a/src/test/java/com/example/dm/util/PasswordGeneratorTest.java b/src/test/java/com/example/dm/util/PasswordGeneratorTest.java new file mode 100644 index 0000000..34f2444 --- /dev/null +++ b/src/test/java/com/example/dm/util/PasswordGeneratorTest.java @@ -0,0 +1,33 @@ +package com.example.dm.util; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +@DisplayName("랜덤 비밀번호 생성 테스트") +class PasswordGeneratorTest { + String password1; + String password2; + + @BeforeEach + void generatePassword(){ + password1 = PasswordGenerator.generatePassword(); + password2 = PasswordGenerator.generatePassword(); + } + + @Test + @DisplayName("랜덤 생성된 패스워드는 길이가 일치하는가?") + void checkPasswordLength() { + assertEquals(password1.length(), password2.length()); + } + + @Test + @DisplayName("랜덤 생성된 패스워드는 중복되지 않는가") + void checkPasswordIsNotDuplicate() { + assert !password1.equals(password2); + } +} \ No newline at end of file