테스트 코드 java.lang.AssertionError: No value at JSON path "$.title" 에러

김명후·2023년 9월 3일

1. 에러 내용

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

http resonse에 Body가 비어있다.
그에 따라 테스트 코드.andExpect(jsonPath("$.title").exists())에서 에러가 발생했다.

java.lang.AssertionError: No value at JSON path "$.title"

	at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:304)
...
Caused by: java.lang.IllegalArgumentException: json can not be null or empty

1.1 내가 작성한 테스트 코드

    @Test
    @DisplayName("Board 데이터 생성 테스트")
    void createBoardTest() throws Exception {

        given(boardService.saveBoard(new BoardDto("title", "content", "boardType", t, t)))
            .willReturn(new BoardResponseDto(123L, "title", "content", "boardType", t, t));

        BoardDto boardDto = BoardDto.builder()
            .title("title")
            .content("content")
            .boardType("boardType")
            .regDate(t)
            .chgDate(t)
            .build();

        Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new GsonLocalDateTimeAdapter())
            .registerTypeAdapter(LocalDateTime.class, new GsonLocalDateTimeAdapter()).create();
        String content = gson.toJson(boardDto);

        mockMvc.perform(
                post("/board")
                    .content(content)
                    .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.title").exists())
            .andExpect(jsonPath("$.content").exists())
            .andExpect(jsonPath("$.boardType").exists())
            .andExpect(jsonPath("$.regDate").exists())
            .andExpect(jsonPath("$.chgDate").exists())
            .andDo(print());

        verify(boardService).saveBoard(new BoardDto("title", "content", "boardType", t, chgT));
    }

하지만 아래와 같이 포스트맨으로 테스트했을 땐 문제가 없다.

그럼 문제는 내 테스트 코드 내에 있다는 의미가 된다.

2. any() & refEq()

2.1 any()

given(boardService.saveBoard(any()))
            .willReturn(new BoardResponseDto(123L, "title", "content", "boardType", t, t));

given() 부분에 any()를 줘서, 어떤 값이 들어가던 willReturn()을 반환하게 한다.
그러나 코드를 이런 식을 수정할 경우, 요청값과 응답값이 같은지를 확인해주지 않는다. 따라서 exists() 부분을 수정해줘야한다.

mockMvc.perform(
                post("/board")
                    .content(content)
                    .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.boardId").value(123L))
            .andExpect(jsonPath("$.title").value("title"))
            .andExpect(jsonPath("$.content").value("content"))
            .andExpect(jsonPath("$.boardType").value("boardType"))
            .andExpect(jsonPath("$.regDate").value("2023-09-02T17:30:00"))
            .andExpect(jsonPath("$.chgDate").value("2023-09-02T17:30:00"))
            .andDo(print());

존재여부만을 검증하는 것이 아닌 실제 값이 일치하는지를 검증하게 만든다.

2.2 refEq()

verify(boardService).saveBoard(new BoardDto("title", "content", "boardType", t, chgT));

테스트 코드 맨 마지막 줄에 있던 verify() 부분을 아래와 같이 수정해준다.

verify(boardService).saveBoard(refEq(boardDto));

refEq() 메서드는 하나의 클래스에서 선택한 필드를 제외하고, given에서 주어진 값과 리플렉션이 동일한 객체인수를 확인하는 데 사용된다.
리플렉션이란, 컴파일 시점에서는 알 수 없는 클래스, 메서드의 이름을 런타임시점에서 메타정보를 이용해 획득하는 기술이다.

설명에 나와있는 동적 바인딩이란, 내가 작성한 코드의 클래스 타입을 자동으로 연결시켜주는다는 의미인 듯 하다.

어쨌든 해결하였다.

0개의 댓글