[Spring] 스프링 슬라이스 테스트 중 406 org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation 에러

kai6666·2022년 8월 22일
0

TIL. Spring

목록 보기
10/11
post-custom-banner

테스트 코드

@Test
@DisplayName("이름조회")
public void getMemberByName() throws Exception{
	Member member1 = new Member(1l, "홍길동", "1234", "남", "대성");
	Member member2 = new Member(2l, "김민희", "5678", "여", "마라");
	Member member3 = new Member(3l, "성대리", "9011", "여", "아발론");

	ResultActions actions = mockMvc.perform(
		get("/v1/members/find?name={name}", member1.getName())
			.accept(MediaType.APPLICATION_JSON)
			);

	MvcResult result = actions
		.andExpect(status().isOk())
		.andReturn();
	}

이름으로 회원 조회하는 기능을 만들고 테스팅을 하던 중 원하던 200번이 아닌 406번 에러가 발생했다.


😵‍💫 에러 메시지

2022-08-22 14:25:49.425  WARN 40047 --- [    Test worker] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation]

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /v1/members/find
       Parameters = {name=[홍길동]}
          Headers = [Accept:"application/json"]
             Body = null
    Session Attrs = {}
    
    (중략)
    
MockHttpServletResponse:
           Status = 406
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

에러 메시지를 보면 Could not find acceptable representation라며 HttpMediaTypeNotAcceptableException 에러를 냈다. HTTP 응답도 처음 보는 406이 왔다. 먼저 이 두 가지에 대해 알아보자.


❓ HttpMediaTypeNotAcceptableException

요청 핸들러가 허용된 응답을 만들어낼 수 없을 때 발생하는 에러라고 한다. 여기서 허용된 응답이란 헤더에 정해놓은 허용 타입이다. 내 코드의 경우 테스트 내에 .accept(MediaType.APPLICATION_JSON)라고 정해놓았기 때문에 JSON 타입만 허용한다.

❓ HTTP 406

The HyperText Transfer Protocol (HTTP) 406 Not Acceptable client error response code indicates that the server cannot produce a response matching the list of acceptable values defined in the request's proactive content negotiation headers, and that the server is unwilling to supply a default representation.

406 에러도 마찬가지로 서버가 허용된 타입의 응답을 생성하지 못할 때 발생하는 통신 에러이다.



해결 - DTO 클래스에 @Getter 추가

기능이 동작하는 과정을 살펴보면 컨트롤러에 구현한 getMemberByName 핸들러 메서드로 member1.getName()의 값인 홍길동이 흘러갈 것이다.

@GetMapping("/find")
    public ResponseEntity getMemberByName(@RequestParam(value = "name") String name) {
        Member member = memberService.getMemberByName(name);
        return new ResponseEntity<>(new SingleResponseDto<>(member), HttpStatus.OK);
    }

이후 홍길동이라는 값은 memberService.getMemberByName() 메서드에 인자로 들어가 레파지토리에서 결과를 찾은 후 member라는 값으로 돌아와 설정된다. 그후 SingleResponseDto라는 DTO 클래스를 거쳐 응답이 전해진다.

요청과 응답 간의 문제이니 여기서부터 문제가 발생했을 거라는 생각이 들었다.

public class SingleResponseDto<T>{
    private T data;

    public SingleResponseDto(T data) {
        this.data = data;
    }
}

DTO 클래스를 보면 생성자만 있고 게터가 없다. 따라서 클래스에 @Getter 애너테이션을 붙여줬다.

@Getter // 추가
public class SingleResponseDto<T>{
    private T data;

    public SingleResponseDto(T data) {
        this.data = data;
    }
}

붙여주니 테스트가 통과되었다. DTO에서 게터가 없으면 응답 내용에 값이 포함되지 않는 문제가 발생한다. (data가 현재 private 변수 때문.) 검색해보니 이 방법 외에도 @JsonProperty라는 애너테이션을 쓰거나 jackson 라이브러리 쓰면 해결할 수 있는 에러라고 한다. (spring-boot-starter-web를 쓴다면 jackson 라이브러리가 디폴트로 포함되어 있다고 한다.)



참고 자료

profile
성장 아카이브
post-custom-banner

0개의 댓글