API 테스트를 하다가 이해가 안되는 상황이 발생했는데, 이런 상황이 발생할 수도 있구나 싶고 누군가에게 도움이 될 수도 있을 것 같아서 짧게 기록해둔다.
다음과 같은 페이징 조회를 하여 특정 테이블에서 추천 인스턴스들을 반환하는 요청을 만든 후 API 테스트를 하던 중 발생하였다.
@GetMapping("/api/v0/hello/suggest")
public ResponseEntity<?> getHello(
@RequestParam(required = false, defaultValue = "") String aFilter
, @RequestParam(required = false, defaultValue = "") String bFilter
, @RequestParam(defaultValue = "-1") int offset
, @RequestParam(required = false, defaultValue = "20") int limit
, @AuthenticationPrincipal @ApiIgnore SecurityMember principal) {
if (offset == -1) {
throw new Exception(EXCEPTION_REASON); // 필수 parameter 누락,
}
...
}
API 테스트를 시도하고 요청을 날려보니, 다음과 같은 에러가 발생하였다.
2024-01-29 12:39:40.879 WARN 8014 --- [nio-8080-exec-6] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "suggest"]
로그를 보면 해당 요청이 수신해야 하는 Parameter 중 타입이 잘못 매핑된 것이 있다는 줄 알아서 이상하다고 생각했다. 왜냐하면 첫 요청은 offset 에 관련해서 예외가 나는지 확인하기 위해서 아무 Parameter 없이 /api/v0/hello/suggest 로만 요청을 시도했기 때문이다.
결론부터 말하자면 그게 아니고, 요청 Matcher 가 중복되기 때문에 발생한 현상이였다. 내가 만든 Hello 란 도메인에 많은 요청 목록을 보면 다음과 같았다.
* POST - /api/v0/hello (CREATE)
...
* GET - /api/v0/hello/{helloId} (세부조회)
...
* DELETE - /api/v0/hello/{helloId} (삭제)
* GET - /api/v0/hello/suggest (추천 Hello 조회, 방금 만든 것)
이와 같은 상황에서, suggest 의 경로로 요청을 날리니, DispatcherServlet 에서 핸들러 매핑을 할 때, 두번째 세부 조회 요청으로 인지하고, helloId 는 Long 타입인데 "suggest" 라는 String 으로 날렸다고 해당 예외를 발생시킨 것이였다. 삭제 요청은 HTTP 메소드가 다르기 때문에 무시할 수 있다.
같은 Method 에서는 기본적인 CRUD 요청외 다른 API 들을 제공할 때, 기본 경로와 중복되는 경로가 없는지 확인하는 것이 중요할 것 같다. Sugget 하는 요청 경로를 수정하니, 정상적으로 동작하는 모습을 확인할 수 있었다. (/api/v0/hello/main/suggest 정도로)
다만, 궁금한 점은 API Tester 로 테스트하는 것은 MockMvc 로 Controller 수신 테스트를 모두 완료한 뒤였다. 그러면 왜 Controller Test 할 때는 해당 예외가 발생하지 않았는지 궁금하다. 아마 MockMvc 로 테스트하는 환경인 @AutoConfigureMockMvc, @SpringBootTest(webEnvironment=SpringBootTest.WebEnvironment.MOCK) 로 환경을 구성하면 조금 다르게 동작하기 때문일 수도 있겠다고 생각이 들었다. 하지만 같은 똑같이 핸들러 매핑을 하는 과정을 겪을 것 같긴 한데, 왜 MockMvc 로 테스트할 때는 발생하지 않았는지 의문이긴 하다
디버거를 걸고 하나씩 파헤쳐보면 알 수도 있을 수도.. 있지만 나중에 하기로 하고 잠깐 미루도록 하겠다. Mock 환경에 대해서 정확하게 이해를 하지 못했기 때문에 의문인 부분이다.
'Logging > Spring' 카테고리의 다른 글
[JPA] OSIV 만 믿었다가 Lazy 로딩에 발등찍힌 썰 (0) | 2024.01.27 |
---|---|
Spring Boot 개발하면서 요즘 드는 생각 (0) | 2023.12.13 |
[문제기록] Lombok @Getter 사용시 boolean 값 처리에 대하여 (0) | 2023.08.30 |
[문제기록] DataJpaTest 시 NoSuchBeanDefinitionException / UnsatisfiedDependencyException (0) | 2023.08.14 |