JUnit test
UserRestController에 대한 테스트를 진행해보려고 한다
먼저 아이디 중복 확인 메소드
/**
* 아이디 중복확인
* @param loginId
* @return
*/
@RequestMapping("/is-duplicated-id")
public Map<String, Object> isDuplicatedId(
@RequestParam("loginId") String loginId) {
//db 조회
UserEntity user = userBO.getUserEntityByLoginId(loginId);
//응답값 만들고 return-> json
Map<String, Object> result = new HashMap<>();
result.put("code", 200);
if (user == null) {
//중복 아닐때
result.put("isDuplicated", false);
} else {
//중복일 때
result.put("isDuplicated", true);
}
return result;
}
test 코드
@AutoConfigureMockMvc
@SpringBootTest
class UserRestControllerTest {
@Autowired
private MockMvc mockMvc;
@Mock
private UserBO userBO;
@InjectMocks
private UserRestController userRestController;
@Test
void 아이디중복확인테스트_중복되지않는경우() throws Exception {
// Given
String loginId = "exampleId";
// Mocking the userBO response
when(userBO.getUserEntityByLoginId(anyString())).thenReturn(null);
// When
Map<String, Object> result = userRestController.isDuplicatedId(loginId);
// Then
assertEquals(200, result.get("code"));
assertFalse((boolean) result.get("isDuplicated"));
}
@Test
void 아이디중복확인테스트_중복되는경우() throws Exception {
// Given
String loginId = "exampleId";
UserEntity mockUserEntity = UserEntity.builder()
.id(1)
.name("Example User")
.loginId(loginId)
.build();
// Mocking the userBO response
when(userBO.getUserEntityByLoginId(anyString())).thenReturn(mockUserEntity);
// When
Map<String, Object> result = userRestController.isDuplicatedId(loginId);
// Then
assertEquals(200, result.get("code"));
assertTrue((boolean) result.get("isDuplicated"));
}
}
@AutoConfigureMockMvc 어노테이션은 Spring Boot 테스트에서 MockMvc를 수동으로 구성 할 필요 없이 자동으로 구성하도록 하는 역할.
이 어노테이션을 사용하면 테스트 클래스에서 MockMvc를 @Autowired로 주입받아서 사용할 수 있다
MockMvc는 Spring MVC 애플리케이션을 테스트하는 데 사용되는 클래스로, HTTP 요청을 모의로 보내고 컨트롤러의 응답을 검증할 수 있다
Mockito를 사용하여 UserBO의 메소드 호출을 가로채어 가짜 응답을 반환하도록 설정
Mockito를 사용하여 UserBO의 getUserEntityByLoginId 메소드가 호출될 때 원하는 결과를 반환하도록 설정하고, UserRestController의 isDuplicatedId 메소드를 호출하여 반환된 결과를 검증
Mockito를 사용하는 이유?
1. 의존성 제어, 격리 : 의존성을 가짜 객체로 대체하여 해당 클래스의 동작을 격리 시킬 수 있다 -> 테스트의 안정성과 신뢰성 높일 수 있음
2. stubbing : 메소드의 반환값을 가짜로 설정할 수 있다, 테스트 시나리오에 따라 특정 메소드가 어떤 값을 반환하도록 조작할 수 있다 -> 다양한 상황에서의 테스트를 수행 할 수 있음
3. 검증 : 메소드가 정확한 매개변수로 호출되었는지를 확인하거나, 메소드 호출 횟수를 검증할 수 있다
회원가입 테스트
/**
* 회원가입
* @param loginId
* @param password
* @param name
* @param email
* @return
*/
@PostMapping("/sign-up")
public Map<String, Object> signUp(
@RequestParam("loginId") String loginId,
@RequestParam("password") String password,
@RequestParam("name") String name,
@RequestParam("email") String email) {
//password 해싱 - md5알고리즘
String hashedPassword = PasswordEncoder.encode(password);
//db insert
Integer id = userBO.addUser(loginId, hashedPassword, name, email);
//응답값
Map<String, Object> result = new HashMap<>();
if (id == null) {
result.put("code", 500);
result.put("errorMessage", "회원가입에 실패했습니다");
} else {
result.put("code", 200);
result.put("result", "성공");
}
return result;
}
test 코드
@Transactional
@Test
void 회원가입_테스트() throws Exception {
// Given
String loginId = "exampleId";
String password = "examplePassword";
String name = "Example User";
String email = "example@example.com";
String hashedPassword = PasswordEncoder.encode(password);
Integer userId = 1; // 예시로 사용자 ID를 지정합니다.
// Mocking the userBO response
when(userBO.addUser(anyString(), anyString(), anyString(), anyString())).thenReturn(userId);
// When & Then
mockMvc.perform(post("/user/sign-up")
.param("loginId", loginId)
.param("password", password)
.param("name", name)
.param("email", email))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200))
.andExpect(jsonPath("$.result").value("성공"));
}
회원가입 성공 테스트는 테스트 성공했지만 회원가입 실패 테스트는 자꾸 회원가입이 성공해서 테스트가 실패했다.
@Transactional
@Test
void 회원가입_실패_테스트() throws Exception {
// Given
String loginId = "testUser";
String password = "examplePassword";
String email = "example@example.com";
String name = "";
// When & Then
mockMvc.perform(post("/user/sign-up")
.param("loginId", loginId)
.param("password", password)
.param("email", email)
.param("name", name))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(400))
.andExpect(jsonPath("$.errorMessage").value("이름을 입력하세요"))
.andExpect(jsonPath("$.result").doesNotExist());
}
회원가입이 실패 할 수 있는 조건을 생각하다가
필수로 제공되어야 하는 정보가 제공되지 않으면 실패조건을 만들 수 있겠다고 생각했다
처음엔 name을 String name = "null"; 로 제공했더니
null이 string으로 인식되어 회원가입이 성공해 테스트 실패
String name = null;로 제공해도 실패
String name = ""; 로 제공해도 실패
sign-up.jsp를 확인 해봐도 !name일 때 회원가입이 되지 않도록 되어있는데,,
그래서 name의 유효성 검사가 필요하다고 판단해
userRestController에 추가해줬다
/**
* 회원가입
* @param loginId
* @param password
* @param name
* @param email
* @return
*/
@PostMapping("/sign-up")
public Map<String, Object> signUp(
@RequestParam("loginId") String loginId,
@RequestParam("password") String password,
@RequestParam("name") String name,
@RequestParam("email") String email) {
// 이름에 대한 유효성 검사 수행
if (name.isEmpty()) {
Map<String, Object> result = new HashMap<>();
result.put("code", 400);
result.put("errorMessage", "이름을 입력하세요");
return result;
}
//password 해싱 - md5알고리즘
String hashedPassword = PasswordEncoder.encode(password);
//db insert
Integer id = userBO.addUser(loginId, hashedPassword, name, email);
//응답값
Map<String, Object> result = new HashMap<>();
if (id == null) {
result.put("code", 500);
result.put("errorMessage", "회원가입에 실패했습니다");
} else {
result.put("code", 200);
result.put("result", "성공");
}
return result;
}
유효성 검사를 추가해주니 회원가입이 실패되고 테스트가 성공했다