Spring 에서 Web Test 에 필요한 Annotation 비교
Spring 에서 Web Test 에 주로 사용되는 @SpringBootTest @AutoConfigureMockMvc @WebMvcTest 를 비교하고 정리해보자.
@SpringBootTest
특징
- Application Context, Servlet container 를 모두 로드함.
- 프로젝트 내부에 있는 모든 Spring bean 을 로드하고, 필요한 의존성이 추가됨.
- 이러한 특징 때문에 외부 환경까지 동일할 경우 실제 환경과 같은 테스트를 수행할 수 있다.
- 그러나 어플리케이션의 크기가 커질수록
context
를 로드하기 위한 시간이 오래 소요되며, 단위 테스트의 의미가 희석된다. - 단위 테스트에서보다는 Spring 전체를 돌리면서 프로그램이 정상적으로 동작하는지 확인하는 때에 확인하는 통합 테스트에서 주로 활용한다.
동작 과정
- 아래는 TestContext 의 동작과정
- 테스트 코드를 실행하면, JUnit5 를 통해서 해당 테스트 코드가 실행된다.
TestContextManager
에 의해서 Spring Context 들이 로드된다. 이 때, 아래 언급한 MockMvc 를 호출하지 않는다면 Servlet Container 까지 함께 로드될 것이다.- 테스트 대상에 대해서 실제와 동등한 Spring bean 들이 DI 로 주입되며 (autowired) 테스트를 진행하고, 결과를 응답받는다.
@AutoConfigureMockMvc
특징
AutoConfigureMockMvc
는@SpringBootTest
와 결합하여 사용한다. 따라서, 필요한 Spring bean 을 함께 로드하여 사용한다.- 그러나 다른 점이 있는데,
@SpringBootTest
와 달리 실제 HTTP 요청을 수행하지 않는다는 점이다.MockMvc
를 통해서 HTTP 요청을 시뮬레이션할 수 있다.- 이 옵션을 사용하게되면 앞단의 웹서버가 작동하지 않는다. 즉, Servlet Container 가 작동하지 않는 것.
- 이 덕택에 상대적으로 더 빠른 테스트가 가능해지며, 독립적인 환경에서 테스트할 수 있다.
- Servlet 동작을
MockMvc
가 시뮬레이션하게 되며, Controller 에 제한된 동작을 검증할 수 있도록 돕는다.- 즉, 컨트롤러에 대한 단위 테스트를 하기 위한 도구이다.
MockMvc
를 통해서 컨트롤러의 엔드포인트를 호출하고 요청을 모방하여 해당 요청에 대한 응답을 검증할 수 있다. 결과적으로 API End point 가 의도한 동작을 수행하는지 검증할 수 있다.MockMvc
→ Servlet Container 의 동작을 Mocking → 가벼운 테스트, 의존성에서 분리된 테스트 → 테스트 대상에 집중하는 단위 테스트 실현- 그러나, AutoConfigureMockMvc + SpringBootTest 환경에서는 Spring bean 을 등록하고 사용한다. 따라서, 해당 목적을 완벽하게 달성하기는 어렵다. 통합 테스트에서 Servlet container 와의 분리의 목적으로 이해된다.
동작 과정
- 테스트 코드에서 MockMvc 를 통해서 Mock Request 를 요청하게 되면, Spring MVC 에서는
TestDispatcherServlet
을 통해 테스트하고자 하는Controller
로 요청한다. - Controller 에서는 해당 코드를 실행하게되고 응답을 할 것이다.
- 다시 테스트 코드에서는 해당 응답을 검증한다.
@WebMvcTest
Annotation that can be used for a Spring MVC test that focuses only on Spring MVC components.
특징
@WebMvcTest
는 오직Spring Mvc Component
에 집중할 수 있도록 한다.- 기존에
@SpringBootTest
에서 자동으로 모든 구성을 하던 것과 달리, 오직 MVC 테스트와 관련한 부분만 구성한다. @WebMvcTest
는 특정 컨트롤러를 대상으로 테스트를 수행하도록 설정한다. 이 때, 해당Controller
와 관련된 Bean 만 로드되며,@Component
@Service
@Repository
는 로드되지 않는다.@Controller
,@ControllerAdvice
,@JsonComponent
,Converter
/GenericConverter
,Filter
,WebMvcConfigurer
andHandlerMethodArgumentResolver
@Component
@Service
@Repository
는 해당하지 않는다.- 서로 어떻게 다른 어노테이션인지 학습이 필요
- 또한
Spring Security
,MockMvc
또한 자동으로 구성한다. @WebMvcTest(DMakerCOntroller.class)
MockMvc
를 사용하기에, 위에서 언급한MockMvc
의 기능을 활용하여Controller
영역에 대한 테스트를 환경에서 보다 더 격리하여 테스트할 수 있도록 한다.
결론
- 모든 환경 / 의존성을 띄우고 통합 테스트 →
@SpringBootTest
- Servlet Container 를 환경에서 제외한 통합 테스트 →
@SpringBootTest
+@AutoConfigureMockMvc
- HTTP 요청 처리 로직에 대한 부분적 통합 테스트 →
@WebMvcTest
(단위 테스트라고는 할 수 없음, 관련된 Bean 이 로드됨. 이 때,Filter
,Interceptor
가 함께 로드됨) - MockMvc 의 역할 →
Servlet Container
의 동작을 Mocking. 조금 더 단위테스트에 가까운 코드를 작성하도록 도움. - 완전한 Unit Test를 작성하고자 한다면 Mockito 를 사용해서 controller method 에 대해서 검증하려고하는 것도 가능할 것.
- 그러나, 테스트 코드를 쓰다보면 서로 겹치는 부분이 많이 발생하곤하는데, 사실 이렇게 되면 테스트 코드에 대해서 상당히 스트레스를 유발할 수 있음.
Controller
코드의 경우E2E Test
정도로 충분하지 않을까 조심스레 생각…
- 그러나, 테스트 코드를 쓰다보면 서로 겹치는 부분이 많이 발생하곤하는데, 사실 이렇게 되면 테스트 코드에 대해서 상당히 스트레스를 유발할 수 있음.
참고
Unit Testing Principles, Practices, and Patterns
- MVC 작동 과정에 대해서 가볍게 정리됨