되자!백엔드개발자
[ERROR] Mock 테스트 중 HttpMessageNotReadableException에러(400에러) 본문
에러 내용
Controller에 대한 테스트 코드를 짜는데 해당 URL의 Controller에 메소드까지 도달하지 못하고 400에러가 났다.
제대로 JSON처리도 했고 @RequestBody도 만들었고
기존에 비슷한 Controller 테스트를 진행했을 때는 잘 됐었는데???!
안되는 원인을 도저히 떠오르지 않았고 경우의 수를 두고 디버깅해본 결과
@RequestBody로 받는 인자가 있을 때 에러가 발생하는 것을 확인하고 열심히 구글링 시작...
테스트코드
@Test
@DisplayName("POST /v1/mentee/{mentoringId} 요청시 해당 멘토링에 멘티 신청을 한다. " +
"멘티신청시 멘토링 count도 +1 되어야한다.")
public void applyMentee() throws Exception {
// given
CreateApplyMenteeReq requestDto = new CreateApplyMenteeReq("멘토링신청합니다.");
// when
mockMvc.perform(MockMvcRequestBuilders.post("/v1/mentee/{mentoringId}", mentoring.getId())
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
.content(mapper.writeValueAsString(requestDto))
).andExpect(status().isOk())
.andDo(print());
// then
System.out.println("requestDto = " + requestDto);
}
컨트롤러
@PostMapping("/{mentoringId}")
public ResponseEntity<Long> applyMentee(@PathVariable("mentoringId") Long mentoringId, @RequestBody CreateApplyMenteeReq dto) {
Long applyMenteeId = menteeService.createApplyMentee(mentoringId, dto);
return ResponseEntity.ok(applyMenteeId);
}
RequestDTO
@ToString
@Getter
@AllArgsConstructor
public class CreateApplyMenteeReq {
private final String description;
// to entity 메서드
}
원인
이전에 진행했던 Controller에서는 RequestDTO로 클라이언트에게 받는 필드가 두개 이상이었으나
이번에 테스트한 메서드에서는 필드가 하나 뿐이어서 직렬화 오류가 났던 것이 원인이었다.
그럼 왜 필드가 하나라면 오류가 날까?
컨트롤러에 DTO가 전달되기 위해서는 ArgumentResolver이 JSON데이터를 Object로 변환하기 위해 MessageConverter을 사용하게 된다.
MessageConverter는 역질렬화를 할 때 아래와 같은 과정을 거치게 된다.
1. Object 생성 : 기본생성자를 호출 (예외: Property 사용 예제)
2. Object 필드 인식 :Setter 혹은 Getter을 이용
3. Object 필드에 값 넣기 : Reflection이용(setter이용X)
만약 해당 클래스(여기서는 RequestDTO)에 기본 생성자가 없을 떄
객체를 생성할 수 있는 다른 방법도 제공해준다.
1. delegateDeser이 null이 아니거나
2. property생성자가 있을경우
이 둘에 해당하지 않으면 역직렬화를 하지 못하고 400에러가 발생했던 것!
1번은 솔직히 뭔지 모르지만 난 설정 안해줬으니 넘어가자
2번은 property생성자가 있었는데 이 경우에 해당되는거 아닌가 싶지만
인자를 하나만 받는 property생성자만 존재한다면 또 상황이 달라진다.
Jackson에서 기본생성자와 getter, setter이 없으면
자동적으로 @JsonCreator를 해당 인자를 받는 생성자에 붙여서 동작하도록 도와준다.
+) @JsonCreator은 역직렬화에 사용되는 생성자를 지정해주는 어노테이션이다.
하지만 단일 생성자에 단일 파라미터가 있는 경우
JackSon이 @JsonCreator을 추가해주는 기능이 동작하지 않아서 해당 에러가 발생했던 것이다.
해결방법
직접 @JsonCreator 붙여준다.
@ToString
@Getter
public class CreateApplyMenteeReq {
private final String description;
@JsonCreator
public CreateApplyMenteeReq(String description) {
this.description = description;
}
}
참고
'개발공부 > ERROR' 카테고리의 다른 글
[ERROR] AWS 인스턴스 인스턴스 상태검사 오류 해결 (0) | 2023.08.04 |
---|---|
[ERROR] GitHub Action '*/gredlew' is not executable. 에러 (0) | 2023.07.13 |
[ERROR] Jackson 직렬화 중 class 못찾는 문제 (0) | 2023.06.30 |
[ERROR] Docker ps, build 등 여러 명령이 실행이 안되는 에러 (0) | 2023.06.28 |
[JavaScript] Post방식으로 int 값을 null로 보내면 error발생 (0) | 2023.02.23 |