Spring과 JUnit을 사용해 개발하면서 통합 테스트를 위해 @SpringBootTest를 많이 사용해왔다. 하지만 누군가 @SpringBootTest에 대해 물어보면 Spring의 통합 테스트를 도와주는 애노테이션이라고 밖에 말할 수 없었다. 그래서 @SpringBootTest가 정확히 어떤 기능을 제공하고 내부적으로 어떻게 동작하는지 궁금해졌다. 이번 글을 통해 공부한 내용을 공유하겠다.
공식문서에서 설명하는 @SpringBootTest
가장먼저 공식문서를 통해 정확히 어떤 기능을 제공하는지 알아봤다.
Annotation that can be specified on a test class that runs Spring Boot based tests. Provides the following features over and above the regular Spring TestContext Framework
공식문서에 따르면 @SpringBootTest는 Spring Boot 기반 테스트를 작성할 때 사용할 수 있는 애노테이션이고 다양한 기능을 제공한다.
각 기능을 살펴보자.
- SpringBootContextLoader를 기본 ContextLoader로 사용한다. 만약 다른 ContextLoader를 사용하고 싶으면 @ContextConfiguration(loader=...)를 사용해 설정할 수 있다.
- 기본적으로 @SpringBootConfiguration을 찾는다. 만약 테스트 클래스 내부에 @Configuration이 있거나, @SpringBootTest의 classes attribute를 명시했다면 찾지 않는다.
- @SpringBootTest의 properties atrributes를 통해 커스텀한 환경 파일을 사용할 수 있다.
- @SpringBootTest의 args attribute를 통해 애플리케이션 인자를 정의할 수 있다.
- 기본적으로 WebEnvironment.MOCK이 설정된다. 만약 다른 WebEnvironment를 사용하고 싶으면 @SpringBootTest의 webEnvironment attribute를 이용해 설정할 수 있다. 지원하는 WebEnvironment는 MOCK, RANMDOM_PORT, DEFINED_PORT, NONE이다. RANDOM_PORT, DEFINED_PORT는 임베디드 웹서버를 이용한다.
- Web test를 위한 TestRestTemplate, WebTestClient 빈을 Context에 등록한다.
공식문서를 읽고 궁금한 부분이 생겼다.
1. SpringBootContextLoader와 Auto Configuration의 관계
2. @SpringBootConfiguration을 찾는 것과 찾지 않는 것의 차이
각각을 자세히 공부했다.
SpringBootContextLoader와 Auto Configuration의 관계
공식문서를 통해 SpringBootContextLoader의 역할을 알아봤다.
A ContextLoader that can be used to test Spring Boot applications (those that normally startup using SpringApplication). Although this loader can be used directly, most test will instead want to use it with @SpringBootTest.
요약하면 Spring Boot application을 테스트 하는데 사용할 수 있는 ContextLoader고 주로 @SpringBootTest를 통해 사용된다.
공식문서를 처음 읽고 SpringBootContextLoader가 Spring Boot application을 테스트 할 때 사용할 수 있는 ContextLoader라고 하여 Auto Configuration과 관련 있는 줄 알았다. 그래서 가설을 증명할 수 있는 근거를 찾기위해 구글링을 했다. 하지만 명확한 정보를 찾을 수 없었다..
결론을 말하자면 Auto Configuration은 SpringFactoriesLoader에서 담당한다. 이는 Spring Boot의 핵심적인 기능으로 @SpringBootTest를 사용하면 Application Context를 로드할 때 SpringFactoriesLoader에서 Auto Configuration을 진행한다. 다시말해, SpringBootContextLoader와 Auto Configuration은 상관없다.
번외 : Auto Configuration 동작 방식
Auto Configuration은 Spring Boot의 가장 핵심적인 기능이다.
이 마법같은 일은 SpringFactoriesLoader와 @Conditional 애노테이션을 이용해 이뤄진다.
간략하게 말하자면, Spring Boot Application이 시작하면 Application Context에 빈들은 다음 순서로 등록된다.
1. 사용자가 정의한 Bean 등록
2. SpringFactoriesLoader에서 Classpath를 확인해 필요할 것 같은 Bean 등록.(Auto Configuration)
위 내용은 글의 메인 주제가 아니기 때문에 이정도로 끝내고 링크를 첨부하겠다.
1. https://medium.com/empathyco/how-spring-boot-autoconfiguration-works-6e09f911c5ce
2. https://www.javadevjournal.com/spring-boot/how-spring-boot-auto-configuration-works/
이대로 마무리하긴 아쉽기 때문에 진짜 그렇게 작동하는지 확인했다.
다음은 내가 작성한 테스트 코드다.
SpringBootContextLoader와 SpringFactoriesLoader에 중단점을 찍었다.
테스트를 실행했다. 그결과 다음 순서로 중단점에 걸렸다.
1. SpringBootContextLoader를 통해 필요한 Bean을 등록한다.
2. SpringFactoriesLoader를 통해 필요한 Bean을 자동 등록한다.
@SpringBootConfiguration을 찾는 것과 찾지 않는 것의 차이
일단 @SpringBootConfiguration에 대해 알아봤다.
Indicates that a class provides Spring Boot application @Configuration. Can be used as an alternative to the Spring's standard @Configuration annotation so that configuration can be found automatically (for example in tests). Application should only ever include one @SpringBootConfiguration and most idiomatic Spring Boot applications will inherit it from @SpringBootApplication.
요약하면 Spring Boot application을 설정하는 클래스를 나타내는 애노테이션이다. 따라서 Spring Boot application에서 한번만 사용해야 한다.
@SpringBootConfiguration을 찾는 다는 의미
@SpringBootConfiguration을 찾는 다는 것은 @SpringBootApplication이 달린 클래스를 찾는다는 것이다. 그리고 여기에 설정된 내용을 Context에 반영한다. 일반적으로 @SpringBootConfiguration은 @SpringBootApplication을 통해 사용하기 때문이다. 그리고 @SpringBootApplication은 내부에 @ComponentScan 애노테이션이 있어 개발자가 정의한 Bean들이 자동으로 Context에 등록된다.
덕분에 테스트 시 Context에 필요한 모든 Bean이 있어 빈의 존재 유무를 신경쓰지 않아도 된다는 장점이 있다. 하지만 필요없는 Bean도 Context에 로딩돼 테스트가 느려질 수 있다.
직접 테스트해봤다.
아래 테스트를 실행했다. 여기서 중요한 점은 테스트에 @Configuration 또는 @SpringBootTest의 classes attribute를 사용하지 않아 @SpringBootConfiguration을 찾게 하는 것이다.
참고로 TempService는 내가 직접 등록한 @Service다. 만약 ComponentScan이 동작한다면 테스트에 성공할 것이다.
테스트가 성공했다.
로그을 통해 좀더 자세히 살펴보자.
로그를 보면 TempService.class가 Scanner에 의해 Component로 식별되었고 Context에 등록되었음을 확인할 수 있다.
@SpringBootConfiguration을 찾지 않는 것의 의미
@Configuration 또는 @SpringBootTest의 classes attribute를 테스트에 명시하면 @SpringBootConfiguration이 달린 클래스를 찾지 않는다. 따라서 테스트에 필요한 빈들을 직접 등록해줘야 하는 번거로움이 있다. 하지만 Context에 필요한 Bean들만 등록되어 테스트가 빨라진다.
이 또한 테스트해보자.
아래 테스트에서 중요한 점은 테스트에 @Configuration을 통해 @SpringBootConfiguration을 찾지 않게 했다.
예상되는 결과로는 TempService가 Context에 없어 DI에 실패해야 한다.
결과
예상대로 Bean을 찾지 못해 DI에 실패했다.
정리
이번 글에서는 @SpringBootTest를 자세히 알아봤다. 여기서 새롭게 알게된 사실을 정리하겠다.
1. @SpringBootTest를 사용한다는 것이 Spring Boot 기반의 테스트를 사용한다는 의미이므로 Auto Configuration은 자동으로 일어난다.
2. 테스트시 모든 빈을 등록하고 싶으면 @SpringBootTest의 classes attribute와 @Configuration을 사용하지 말자.
긴글 읽어주셔서 감사합니다. 도움이 되셨다면 공감 또는 댓글 부탁드립니다! 추가로 제가 잘못 이해한 내용이 있다면 댓글로 피드백 남겨주세요.
'Spring' 카테고리의 다른 글
Spring's STOMP support 파헤치기 (0) | 2023.06.02 |
---|---|
Spring Websocket Trobleshooting!! (feat. Decorator Pattern) (0) | 2023.05.21 |
Spring Cloud GateWay의 non-blocking server (0) | 2022.12.31 |
@RequestBody (0) | 2022.06.10 |
@JdbcTest와 @DataJdbcTest (0) | 2022.05.21 |