[ERROR] MockMvc org.springframework.http.converter.HttpMessageNotReadableException

반응형

1. 문제

JUnit test에서 MockMvc를 사용해 POST API를 호출할 때 JSON content를 API에서 제대로 Parsing 하지 못해 HttpMessageNotReadableException이 발생할 수 있다.

Test

@Test
public void testPost() throws Exception{
    //language=JSON
    String json = "{\n" +
            "  \"title\" : \"Greetings\",\n" +
            "  \"value\" : \"Hello World\"\n" +
            "}\n";

    mockMvc.perform(
            post("/hello/post")
            .contentType(MediaType.APPLICATION_JSON)
            .content(json))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.title", Matchers.is("Greetings")))
            .andExpect(jsonPath("$.value", Matchers.is("Hello World")))
            .andExpect(jsonPath("$.*", Matchers.hasSize(2)));
}

API

@PostMapping(value ="/post", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public Hello post(@RequestBody Hello hello){
    return hello;
}

따라서 아래와 같이 400 ERROR를 return 한다.

image.png

2. 원인

API에서 @RequestBody로 전달받을 객체로 사용한 Hello의 접근제한자가 문제였다. 간단히 Hello를 private로 API를 작성한 Controller 내부에 선언해놨었는데, 이 때문에 HttpServlet이 JSON 메세지를 Hello 객체라고 인식하지 못했다.

전체 Controller 코드는 아래와 같다.

HelloResource

@RestController
@RequestMapping("/hello")
public class HelloResource {

    @PostMapping(value ="/post", consumes = MediaType.APPLICATION_JSON_VALUE
                , produces = MediaType.APPLICATION_JSON_VALUE)
    public Hello post(@RequestBody Hello hello){
        return hello;
    }

    private class Hello {
        private String title;
        private String value;

        public Hello(){

        }

        public Hello(String title, String value) {
            this.title = title;
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getTitle(){
            return title;
        }

        public void setTitle(String title){
            this.title = title;
        }
    }
}

3. 해결

private으로 선언한 Hello class를 public static으로 변경하면 된다. 변경 후 테스트하면 아래와 같이 테스트가 정상적으로 통과한다.

HelloResource

@RestController
@RequestMapping("/hello")
public class HelloResource {

    @PostMapping(value ="/post", consumes = MediaType.APPLICATION_JSON_VALUE
                , produces = MediaType.APPLICATION_JSON_VALUE)
    public Hello post(@RequestBody Hello hello){
        return hello;
    }

    public static class Hello {
        private String title;
        private String value;

        public Hello(){

        }

        public Hello(String title, String value) {
            this.title = title;
            this.value = value;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getTitle(){
            return title;
        }

        public void setTitle(String title){
            this.title = title;
        }
    }
}

image.png


추천서적

 

스프링 부트와 AWS로 혼자 구현하는 웹 서비스

COUPANG

www.coupang.com

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음


반응형

댓글

Designed by JB FACTORY