테스트 속도 향상을 위한 StandaloneSetup과 Custom ExceptionResolver 활용법

S-J LEE·2025년 3월 20일

TEST

목록 보기
1/2

테스트 속도를 증가시키기 위해 @SpringBootTest@WebMvcTest와 같이 전체 스프링 컨텍스트를 로드하는 방식 대신,
MockMvcBuilders.standaloneSetup(controller)를 사용하는 경우가 있습니다.
이 방법을 사용하면 컨트롤러 단위 테스트가 빠르게 실행되지만, HTTP 요청 처리 시 스프링 부트에서 제공하는 기본 ExceptionResolver나 기타 설정이 적용되지 않기 때문에,
특히 잘못된 HTTP 요청에 대해 정상적인 400 Bad Request 응답을 기대할 때 문제가 발생할 수 있습니다.

문제 상황

HTTP 요청 본문에 잘못된 데이터가 포함되어 있을 경우,
Jackson이 역직렬화 중 MissingKotlinParameterException을 발생시키고, 이를 HttpMessageNotReadableException으로 감싸게 됩니다.
그러나 StandaloneSetup 환경에서는 기본 ExceptionResolver가 등록되지 않으므로,
해당 예외가 제대로 처리되지 않고 500 Internal Server Error가 발생할 수 있습니다.

해결 방법: Custom ExceptionResolver 적용

이 문제를 해결하기 위해,
테스트 환경에서 커스텀 ExceptionResolver를 만들어 예외를 잡아 400 응답으로 매핑하는 방법을 사용할 수 있습니다.
무수한 시도를 해본 결과, 이 방식이 가장 간단하고 효과적인 해결책으로 보입니다.

일반적으로는 의존성 주입 객체를 mock으로 생성하고, 컨트롤러에 주입한 후,
아래와 같이 customExceptionResolver를 등록합니다.

컨트롤러와 MockMvc 설정 예시

val service: TestService = mock()
val controller = TestController(service)
mockMvc = MockMvcBuilders
    .standaloneSetup(controller)
    .setHandlerExceptionResolvers(customExceptionResolver)
    .build()

Custom ExceptionResolver 구현

아래 코드는 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 응답을 반환하는 동작을 테스트할 수 있습니다.

이 방법은 빠른 테스트 실행과 원하는 예외 처리 흐름을 동시에 재현할 수 있는 좋은 해결책입니다.

profile
MSA 와 관련된 기반 기술에 관심이 많습니다.

0개의 댓글