@SpringBootTest가 붙으면 Application Context에 의존성 주입 오류(NoSuchBeanDefinitionException) 없이 테스트에 필요한 모든 의존성을 제공해준다. 여러 객체들을 빈으로 등록해서 전체적인 통합 테스트를 진행할 때 사용할 수 있다.
@SpringBootTest 내부 확인
맨 아래부터 보면 Junit Jupitier(Junit5의 일부)의 SpringExtension을 등록한 것을 볼 수 있다. SpringExtention은 Spring TestContext 프레임워크를 Junit5의 Jupiter 프로그래밍 모델에 통합한다.
이 extension은 테스트 프레임워크와 스프링의 원활한 통합을 위해 필수적이다.
@BootstrapWith는 Sprint TestContext 프레임워크를 부트스트랩하는 방법을 결정하는 데 사용되는 클래스 수준 메타데이터를 정의한다.
메인 스프링부트 시작 클래스 (@SpringBootApplication)을 찾아 Context 구성을 검색하고 그에 따라 Context를 띄우는 작업을 한다.
(컴포넌트 스캔 메커니즘이 트리거 되고 모든 auto-configuration이 적용)
마지막 4개의 어노테이션(@Ingerited, @Document, @Retention, @Target)은 java.lang.annotation의 자바 관련 어노테이션이다. 커스텀 어노테이션 관련 메타 데이터를 정의하며 어노테이션을 적용할 범위(클래스 또는 메서드 수준)와 유지 기간을 제한한다.
Configuration Options for Integration Tests With @SpringBootTest
@SpringBootTest의 속성으로 webEnvironment를 구성할 수 있다.
이 값은 테스트 대상 context 유형에 영향을 미치고 실제로 내장 서블릿 컨테이너(톰캣)를 띄우는지의 여부를 정한다.
The Default: WebEnvironment.MOCK
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
MOCK은 아무것도 지정하지 않았을 때 적용되는 기본값이다. 스프링은 테스트를 위한 mock 된 서블릿 환경을 가지는 WebApplicationContext를 생성한다.
이는 MockMvc를 사용하고 @WebMvcTest를 사용해서 스프링 MVC 컨트롤러 테스트를 작성하는 것과 유사하다. (MockMvc를 이용하여 테스트를 할 수 있다.)
@WebMvcTest와의 차이점은 테스트 컨텍스트에 포함되는 스프링 빈의 숫자이다. @WebMvcTest는 웹 관련 빈만 채우는 반면 @SpringBootTest는 전체 컨텍스트를 채운다.
이 설정에서는 내장 서블릿 컨테이너(톰캣)를 사용하지 않는다.
WebEnvironment.RANDOM_PORT
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
이 설정에서 스프링은 통합 테스트를 위한 WebApplicationContext를 생성하고 랜덤한 포트에서 실제 내장 서블릿 컨테이너를 띄운다.
테스트를 위해 WebTestClient나 RestTestTemplate인 HTTP 클라이언트를 자동 주입받아 사용할 수 있다.
이 설정은 HTTP 엔드 포인트에 엑세스하고 통합 테스트를 작성할 때 기본적으로 선택하는 값이다.
@SpringBootTest를 항상 사용해야할까?
모든 테스트에 @SprintBootTest를 붙이는 것은 좋지 않다.
첫 번째로 애플리케이션 컨텍스트가 언제나 실행될 수 있는지 확인해 봐야 한다. 통합할 외부 인프라가 없다면 언제든 시작할 수 있겠지만 DB 등의 외부 시스템을 통합하는 즉시 이 작업은 복잡해진다.
두 번째로 @SpringBootTest를 사용하면 단위 테스트를 진행함에도 불구하고 전체 컨텍스트를 띄워야 하고 @MockBean을 사용해 모든 의존 객체를 mock 객체로 사용해야 한다.
위 테스트에서는 전체 컨텍스트를 띄울 필요 없이 JUnit과 Mockito만으로 테스트가 가능하다.
일반적으로 단위 테스트를 가능한 한 많이 다루고, 적용할 때만 @SpringBootTest를 슬라이스로 사용하여 통합 테스트는 일부만 적용해야 한다.
@SprintBootTest를 많이 사용하면 컨텍스트를 띄우고 테스트를 수행하면서 캐싱된 컨텍스트를 재사용할 수 없게 되어 빌드 시간이 늘어난다. (많은 비용 발생)
Spring Boot Test Slices
스프링 부트는 다양한 슬라이스(웹, DB 등) 테스트를 위한 뛰어난 자원을 제공한다. 이렇게 하면 전체 스프링 컨텍스트를 띄우지 않고 일부 빈들만으로 컨텍스트를 생성함으로써 애플리케이션의 특정 부분에 대한 테스트를 단독으로 작성할 수 있다.
Testing the Web Layer With @WebMvcTest
이 어노테이션을 사용하면 스프링 MVC에 관한 컴포넌트들로 스프링 컨텍스트를 띄울 수 있다.
컨텍스트에 포함되는 빈
@Controller, @ControllerAdvice, @JsonComponent, Converter, Filter, WebMvcConfigurer
포함되지 않는 빈
@Service, @Component, @Repository등
또한 Spring Sequrity를 사용하여 엔드 포인트를 보호하는 경우 큰 도움을 받을 수 있다. 보안 규칙이 자동으로 구성되며 시큐리티 테스트 의존성을 포함하면 인증된 사용자를 쉽게 mock 할 수도 있다.
이 어노테이션은 mock 서블릿 환경을 제공하므로 RestTemplate과 같은 애플리케이션에 액세스 할 수 있는 포트가 없다. 따라서 auto-configured된 MockMvc를 이용해 엔드 포인트에 엑세스할 수 있다.
일반적으로 @MockBean을 사용하여 컨트롤러의 의존 빈을 mock으로 대체한다.
Testing your JPA Components With @DataJpaTest
JAP 관련 부분을 테스트할 수 있다.
컨텍스트에 포함되는 빈
@Repository, EntityManager, TestEntityManager, DataSource
포함되지 않는 빈
@Service, @Component, @Controller
기본적으로 이 어노테이션은 내장 데이터베이스(H2)를 자동으로 사용한다.
모든 테스트는 트랜잭션 내에서 실행되며 실행 후 롤백된다.
Testing JDBC Access With @JdbcTest
JdbcTemplate를 사용할 때 사용할 수 있다.
컨텍스트에 포함되는 빈
JdbcTemplate, DataSource
포함되지 않는 빈
@Service, @Component, @Controller, @Repository
이 어노테이션도 내장 데이터베이스를 자동으로 사용한다.
정리
- @SpringBootTest는 통합 테스트를 위한 강력한 도구다.
- 하지만 모든 테스트가 @SpringBootTest로 실행되어야 하는 건 아니다.
- 기본 webEnvironment는 Mock이다.
- 컨텍스트 구성과 환경을 조정하기 위한 여러 전략이 있다.
- 서로 다른 스프링 테스트 컨텍스트 구성을 띄울 때 빌드 시간이 늘어난 다는 것을 인지하자.
가능한 한 빨리 실행되는 단위 테스트를 많이 다루고, 슬라이스 컨텍스트를 적용할 수 있을 때 적용하고, @SrpingBootTest를 사용하는 일부 통합 테스트에서 전체 기능을 확인해야 한다.
참고
https://rieckpil.de/guide-to-springboottest-for-spring-boot-integration-tests/?amp
https://rieckpil.de/spring-boot-test-slices-overview-and-usage/
'스프링 > 테스트' 카테고리의 다른 글
TestContainer와 H2의 장점만 골라먹기 (1) | 2024.01.22 |
---|---|
@Mock vs @MockBean (0) | 2022.05.01 |