본문 바로가기
PlayGround/마실가실 리팩토링

[1년 후 마실가실] Controller Test Code - mockMvc.perform()

by HJ0216 2024. 10. 17.

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://github.com/f-lab-edu/travel-board/blob/fe06a09f944df3bc35b2c1edf06b5fe662a18c89/api-user/src/unitTest/java/com/user/controller/AuthControllerTest.java

 

travel-board/api-user/src/unitTest/java/com/user/controller/AuthControllerTest.java at fe06a09f944df3bc35b2c1edf06b5fe662a18c89

트래픽이 많은 상황을 가정한 여행지 추천 및 리뷰 게시판을 만들고 있습니다. Contribute to f-lab-edu/travel-board development by creating an account on GitHub.

github.com

https://chordplaylist.tistory.com/222

 

[04] User Test 코드 작성

이전글 [03] 게시된 포스트 삭제 이전글 [03] 게시된 포스트 수정 이전글 [03] 게시된 모든 포스트 목록 보기 이전글 [03] 포스트 등록 만들기 체크 사항 로그인이 되어있어야 하며, 토큰으로 인증을

chordplaylist.tistory.com