Projects/Personal project - 게시판 만들기

Mock test 단계에서 발생한 MockHttpServletResponse: body is empty

마손리 2023. 6. 8. 16:17

드디어 게시판 프로젝트의 마지막 단계만 남았다!

 

마지막으로 Mock test를 진행하면서 Rest docs를 이용해 API문서를 만드는 도중에 발생한 문제이다.

 

 

문제발생

앞서 post 요청에 대한 테스트 코드를 작성한 뒤 통과하고 patch 요청에 대한 코드를 작성한 이후 테스트가 실패하게되었다.

 

먼저 작성한 테스트 코드이다.

@WebMvcTest(value = MemberController.class)
@MockBean(JpaMetamodelMappingContext.class)
@AutoConfigureRestDocs
public class MemberControllerRestDocsTest implements MemberControllerTestHelper {
    ...
    ...
    @Test
    @WithMockUser
    public void patchMemberTest() throws Exception {
        long memberId = 1L;
        MemberDto.Patch patch = MemberDto.Patch.builder()
                .email("modified@email.com")
                .name("modifiedName")
                .password("Modified12")
                .build();

        String content = gson.toJson(patch);

        MemberDto.Response response = MemberDto.Response.builder()
                .memberId(1)
                .email("modified@email.com")
                .name("modifiedName")
                .memberStatus(Member.MemberStatus.MEMBER_ACTIVE)
                .build();
                
        given(mapper.memberPatchToMember(Mockito.any(MemberDto.Patch.class))).willReturn(new Member());

        given(memberService.createMember(Mockito.any(Member.class))).willReturn(new Member());

        given(mapper.memberToMemberResponse(Mockito.any(Member.class))).willReturn(response);

        ResultActions actions = mockMvc.perform(
                patch("/v1/members/{member-id}", memberId)
                        .with(SecurityMockMvcRequestPostProcessors.csrf())
                        .accept(MediaType.APPLICATION_JSON)
                        .contentType(MediaType.APPLICATION_JSON)
                        .content(content)
        );


        actions
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.data.memberId").value(1))
                .andExpect(jsonPath("$.data.email").value(patch.getEmail()))
                .andExpect(jsonPath("$.data.memberStatus").value("MEMBER_ACTIVE"));
    }

}

 

특이할 것 없는 테스트 코드이다.

 

요청의 바디와 응답의 바디를 생성해주고 Mokcito의 given 메서드를 사용하여 특정 메서드 호출시 지정된 데이터가 리턴되도록 설정해주고 가짜 요청을 보내주었는데... 테스트가 실패하였다.

 

테스트 로그를 살펴보면

 

MockHttpServletRequest:
      HTTP Method = PATCH
      Request URI = /v1/members/1
       Parameters = {_csrf=[38e562a8-d854-4318-aab4-8b00760456a5]}
          Headers = [Content-Type:"application/json;charset=UTF-8", Accept:"application/json", Content-Length:"89"]
             Body = {"memberId":0,"email":"modified@email.com","name":"modifiedName","password":"Modified12"}
...
...
MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json", 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
             Body = {"data":null}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

MockHttpServletRequest의 Body를 살펴보면 분명 입력한 가짜 요청이 잘 들어갔다.

 

하지만 MockHttpServletResponse의 Body를 살펴보니 null이 뜨는 것을 확인 할 수 있었다.

 

 

문제해결 시도

혹시 이전에 코드를 수정하는 과정에서 뭔가 잘못이 일어났을 가능성을 생각하여 애플리케이션 서버를 가동시키고 Postman을 이용하여 해당 요청에 대한 응답을 확인해 보았다.

 

다행히(?)도 직접 요청을 보냈을때에는 별다른 특이사항이 발생하지 않았다.

 

그렇다는것은 테스트코드가 잘못되었다는 것이니 테스트 코드를 좀더 구체적으로 수정해 보았다.

 

@WebMvcTest(value = MemberController.class)
@MockBean(JpaMetamodelMappingContext.class)
@AutoConfigureRestDocs
public class MemberControllerRestDocsTest implements MemberControllerTestHelper {
    ...
    ...

    @Test
    @WithMockUser
    public void patchMemberTest() throws Exception {
    	...
    	...
		
        // 멤버 객체 생성
        Member member = new Member();
        member.setMemberId(1L);
        member.setEmail("modified@email.com");
        member.setName("modifiedName");
        member.setMemberStatus(Member.MemberStatus.MEMBER_ACTIVE);

        given(mapper.memberPatchToMember(Mockito.any(MemberDto.Patch.class))).willReturn(new Member());

        given(memberService.createMember(Mockito.any(Member.class))).willReturn(new Member());
		
        //생성된 멤버 객체를 맵퍼에 전달
        given(mapper.memberToMemberResponse(member)).willReturn(response); 
	...
        ...
    }

}

 

Entity와 응답 Dto간의 맵퍼에 실제와 같이 직접 객체를 생성하여 전달해 주었지만... 결과는 같았다.

 

 

해결법

결국 몇시간을 스택 오버 플로를 뒤저 해결법을 찾게되었다

 

given(mapper.memberToMemberResponse(Mockito.any())).willReturn(response);

 

위와 같이 Mockito.any() 메서드에 어떤 매개변수도 주지 않게되면 무조건 willReturn() 메서드로 전달된 객체가 반환이 된다는 글이었다.

 

 

 

다행히 테스트는 성공하게 됬지만 뭐가 잘못되서 테스트가 실패했던건지... 분명 이전에 같은 방식으로 테스트 코드를 작성했을땐 잘 작동했던거 같은데 왜그런지 원인을 찾지 못하게되어 뭔가 찝찝한 마무리가 되었다...