1년 전 진행했던 마실가실 프로젝트를 🛠️리팩토링하며 정리한 내용입니다.
Controller Test Code의 mockMvc.perform()..
근데, ArgumentCaptor를 곁들인..
JWT 난관은 구현에서 끝나지 않았습니다.
Test Code가 기다리고 있었습니다.
앞뒤양옆으로 봐도 똑같은 DTO 객체를 전달하는데, 자꾸 아니라며 다르다며 우겨대는 테스트 코드와 싸우다 이유를 찾게 되어 글로 정리해보고자 합니다.
UserControllerTest.java
문제
MockHttpServletResponse:
Status = 200
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: No value at JSON path "$.accessToken"
Status는 200으로 로그인에 성공했으나, return값인 Token 정보가 Body로 return이 되지 않음
원인
given(userService.login(loginDto)).willReturn(expectedResult);
loginDto 객체를 userService의 login 함수에 인자로 전달할 경우, expextedResult Token 정보가 반환됨
⭐ loginDto 객체가 인자로 전달되어야 함
ResultActions result = mockMvc.perform(post("/api/v2/users/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginDto)));
content에 loginDto가 objectMapper.writeValueAsString을 통해 전달됨
같은 참조값을 갖는 loginDto인지 확인하기 위해 ArgumentCaptor 사용
ArgumentCaptor<LoginRequestDTO> captor = ArgumentCaptor.forClass(LoginRequestDTO.class);
verify(userService).login(captor.capture());
LoginRequestDTO capturedDto = captor.getValue();
System.out.println("Original loginDto instance address: " + System.identityHashCode(loginDto));
// Original loginDto instance address: 1379756869
System.out.println(
"Captured loginDto instance address: " + System.identityHashCode(capturedDto));
// Captured loginDto instance address: 1329520064
ArgumentCaptor
* LoginRequestDTO 클래스에 대해 Mockito가 내부적으로 메서드 호출 시 전달된 인자를 캡처하여, 테스트에서 검증
* capture()
* 특정 메서드가 호출되었는지 검증할 때, 해당 메서드의 인자로 전달된 값을 ArgumentCaptor로 캡처
instance address가 상이한 이유
* objectMapper.writeValueAsString(loginDto)를 통해 loginDto 객체가 JSON 문자열로 변환
* mockMvc.perform()은 JSON 문자열을 HTTP 요청 본문으로 전송
* 서버 측에서 이 JSON 문자열을 받아서 새로운 LoginRequestDTO 객체로 역직렬화
해결
1. 모든 인자에 대해 expectedResult를 반환하도록 함
given(userService.login(any())).willReturn(expectedResult);
2. 모든 필드값이 동일할 경우, expextedResult를 반환하도록 함
given(userService.login(argThat(dto ->
dto.getEmail().equals(loginDto.getEmail()) &&
dto.getPassword().equals(loginDto.getPassword())
))).willReturn(expectedResult);
🙋♀️
본 포스트는 공부 목적으로 작성하였습니다.
보시는 도중 잘못된 부분이나 개선할 부분이 있다면 댓글로 알려주시면 수정하도록 하겠습니다.
📑
참고 자료
https://chordplaylist.tistory.com/222
'PlayGround > 마실가실 리팩토링' 카테고리의 다른 글
[1년 후 마실가실] Spring Security + JWT - LoginFilter (0) | 2024.10.27 |
---|---|
[1년 후 마실가실] User Error Code HttpStatus (1) | 2024.10.19 |
[1년 후 마실가실] API 문서화 도구 - Spring REST Docs (4) | 2024.10.10 |
[1년 후 마실가실] Issue 및 PR Template 설정과 Label 변경 (4) | 2024.10.09 |
[1년 후 마실가실] 로그 설정 (2) | 2024.10.03 |