테스트 코드를 작성하다가 만나게 된 난감한 문제 중 하나
기존의 코드로 테스트를 실행할 경우
분명히 테스트도 통과했다고 뜨고, 상태 코드도 200을 반환하는데
Body의 값이 텅 비어있는 경우가 발생했다.
그렇다고 오류가 발생한 것도 아니었는데 문제는
MockMVC 중 Json Response 검증하는 JsonPath()를 사용할 때이다.
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
사실 나는 나는 jsonPath()를 통해 응답 Response 중 message의 값이 일치하는지를 추가로 검증하고 싶었는데
.andExpect(MockMvcResultMatchers.jsonPath("$.message").value("로그인에 성공하였습니다."));
이 코드를 추가하고, 테스트를 다시 실행하면 이와 같은 에러를 만나게 된다.
java.lang.AssertionError: No value at JSON path "$.message"
at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:304)
at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:99)
at org.springframework.test.web.servlet.result.JsonPathResultMatchers.lambda$value$2(JsonPathResultMatchers.java:111)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:214)
at com.zipkimi.user.controller.UserLoginControllerTest.loginSuccessTest(UserLoginControllerTest.java:137)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at ... (생략)
그래서 다시 찾아본 결과
기존의 when절 메서드에서 수정이 필요했다!
when(userLoginService.login(request)).thenReturn(successResponse);
이러한 흐름의 코드이다.
해결 방법
이 코드의 login 메서드에 전달하는 인자를 any()로 변경하는 것이다.
when(userLoginService.login(any(UserLoginRequest.class))).thenReturn(successResponse);
어떠한 객체도 처리할 수 있도록 any()를 통해, 어떤 요청이 들어가든 successResponse를 반환해줄 것이다.
TokenResponse successResponse = TokenResponse.builder().message("로그인에 성공하였습니다.").build();
수정 후 다시 테스트를 실행해보면 다음과 같이 통과하는 것을 확인할 수 있다.
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8", X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"]
Content type = application/json;charset=UTF-8
Body = {"message":"로그인에 성공하였습니다."}
Forwarded URL = null
Redirected URL = null
Cookies = []
원인은 테스트에서 의도한 대로 이 부분의 객체가 같은 것으로 인식되지 않고 서로 다른 두 개의 객체로 인식을 해서인듯 하다.
when(userLoginService.login(request)).thenReturn(successResponse);
출처 : https://stackoverflow.com/questions/65157415/mockmvc-jsonpath-response-has-empty-body