테스트 속도를 증가시키기 위해 @SpringBootTest나 @WebMvcTest와 같이 전체 스프링 컨텍스트를 로드하는 방식 대신,
MockMvcBuilders.standaloneSetup(controller)를 사용하는 경우가 있습니다.
이 방법을 사용하면 컨트롤러 단위 테스트가 빠르게 실행되지만, HTTP 요청 처리 시 스프링 부트에서 제공하는 기본 ExceptionResolver나 기타 설정이 적용되지 않기 때문에,
특히 잘못된 HTTP 요청에 대해 정상적인 400 Bad Request 응답을 기대할 때 문제가 발생할 수 있습니다.
HTTP 요청 본문에 잘못된 데이터가 포함되어 있을 경우,
Jackson이 역직렬화 중 MissingKotlinParameterException을 발생시키고, 이를 HttpMessageNotReadableException으로 감싸게 됩니다.
그러나 StandaloneSetup 환경에서는 기본 ExceptionResolver가 등록되지 않으므로,
해당 예외가 제대로 처리되지 않고 500 Internal Server Error가 발생할 수 있습니다.
이 문제를 해결하기 위해,
테스트 환경에서 커스텀 ExceptionResolver를 만들어 예외를 잡아 400 응답으로 매핑하는 방법을 사용할 수 있습니다.
무수한 시도를 해본 결과, 이 방식이 가장 간단하고 효과적인 해결책으로 보입니다.
일반적으로는 의존성 주입 객체를 mock으로 생성하고, 컨트롤러에 주입한 후,
아래와 같이 customExceptionResolver를 등록합니다.
val service: TestService = mock()
val controller = TestController(service)
mockMvc = MockMvcBuilders
.standaloneSetup(controller)
.setHandlerExceptionResolvers(customExceptionResolver)
.build()
아래 코드는 HttpMessageNotReadableException을 처리하여,
내부 원인이 MissingKotlinParameterException인 경우 400 Bad Request 응답을 반환하도록 하는 커스텀 ExceptionResolver의 예시입니다.
// 커스텀 ExceptionResolver 생성
val customExceptionResolver = object : ExceptionHandlerExceptionResolver() {
override fun resolveException(
request: HttpServletRequest,
response: HttpServletResponse,
handler: Any?,
ex: Exception
): ModelAndView? {
if (ex is HttpMessageNotReadableException && ex.cause is MissingKotlinParameterException) {
response.status = SC_BAD_REQUEST
return ModelAndView() // 빈 ModelAndView 반환
}
return super.resolveException(request, response, handler, ex)
}
}.apply { afterPropertiesSet() }
이렇게 customExceptionResolver를 적용하면,
잘못된 HTTP 요청에 대해 400 Bad Request 응답을 기대한 것처럼 동작시킬 수 있습니다.
전체 스프링 컨텍스트 vs. StandaloneSetup:
StandaloneSetup 방식은 전체 스프링 컨텍스트를 로드하지 않으므로,
기본으로 등록되는 ExceptionResolver나 MessageConverter 등의 설정이 자동으로 반영되지 않습니다.
따라서 필요한 경우, 위와 같이 수동으로 필요한 컴포넌트를 등록해주어야 합니다.
테스트 환경의 복잡도:
만약 테스트 환경에서 기본 스프링 부트 설정을 그대로 재현하고 싶다면,
MockMvcBuilders.webAppContextSetup(webApplicationContext)를 사용하는 방법도 고려해볼 수 있습니다.
단, 이 경우 테스트 실행 속도가 느려질 수 있으므로,
속도와 설정의 균형을 잘 맞추어야 합니다.
위와 같이 설정하면,
잘못된 HTTP 요청에 대해 StandaloneSetup 환경에서도
스프링 부트가 실제 운영환경에서와 동일하게 400 응답을 반환하는 동작을 테스트할 수 있습니다.
이 방법은 빠른 테스트 실행과 원하는 예외 처리 흐름을 동시에 재현할 수 있는 좋은 해결책입니다.