동작 원리
TestContext 를 bootstrap 하는 원리
테스트 컨텍스트란, 테스트시 application context 를 말하며 애플리케이션의 구성 정보를 구성하는 것을 말한다. 예를들어,애플리케이션의 Bean 을 로드하는 것도 이에 포함된다고 할 수 있다.
그렇다면, 이 테스트 컨텍스트는 어떻게 로드 될까? 이를 알기 위해서 @SpringBootTest 어노테이션을 확인해보자.
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
// TestContextBootstrapper 구현체 : SpringBootTestContextBootstrapper
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
public @interface SpringBootTest
테스트 프레임워크(Junit)의 ExtendWith 은 테스트의 기능을 확장하기 위한 것인데, SpringBootTest 에서는 SpringExtension 을 사용하고 있다.
SpringExtension 코드를 따라가보면, @BootStrapWith 어노테이션에 명시된 TestContextBootStraper 를 이용하여 테스트 컨텍스트를 구성한다. 즉, 스프링에서 통합 테스트(@SpringBootTest) 를 할 때, TestContextBootstrapper 인터페이스 구현체가 테스트 컨텍스트를 로드한다.
무엇으로 context 를 구성하는가?
해당 부분은 2편에서 추가적으로 다루고자 한다.
https://pius712.tistory.com/36
테스트에 사용되는 어노테이션과 친해지기
테스트 기능 확장하기 - @ExtendWith
SpringBootTest 어노테이션에는 @ExtendWith(SpringExtension.class) 어노테이션이 붙어있는데, 이건 무엇을 뜻할까?
참고로 JUnit4 에서는 @RunWith(SpringRunner.class) 어노테이션이 사용되었으나,
JUnit5 에서는 @ExtendWith(SpringExtension.class) 어노테이션으로 대체되었다.
RunWith 과 Extension 자체가 동일한 것은 아니지만, SpringRunner 의 동작을 Extension 을 구현하는 방식으로 변경된 것 같다.
ExtendWith 을 통해서 테스트 관련 확장 기능을 제공할 수 있다.
JUnit 5 확장 모델은 다음과 같은 다양한 인터페이스를 통해 확장을 구현할 수 있음
- BeforeAllCallback / AfterAllCallback
- BeforeEachCallback / AfterEachCallback
- TestExecutionExceptionHandler
- ParameterResolver
- 등등
이러한 인터페이스를 구현하여, 테스트 실행 전후에 특정 작업을 수행하거나, 테스트 메소드에 파라미터를 주입하는 등의 기능을 추가할 수 있다.
예를들어, 각 테스트의 수행 시간을 체크하는 기능을 아래처럼 만들 수 있다.
// 테스트 extension 생성
class LoggingExtension : TestWatcher {
private val log: Logger = LoggerFactory.getLogger(javaClass)
private var startTime: Long = 0
override fun testSuccessful(context: ExtensionContext) {
val duration = System.currentTimeMillis() - startTime
log.info("Test '${context.displayName}' passed after $duration ms")
}
override fun testFailed(context: ExtensionContext, cause: Throwable) {
val duration = System.currentTimeMillis() - startTime
log.info ( "Test '${context.displayName}' failed after $duration ms" )
}
}
// 적용하는 법
@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
@ActiveProfiles("local")
@ExtendWith(LoggingExtension::class) // 적용
abstract class IntegrationTest
Profile 변경하기 - @ActiveProfiles
기본적으로 테스트 수행시 아무런 설정을 하지 않으면 profile 이 “default” 값으로 테스트가 실행된다.
profile 을 변경하기 위해서는 @ActiveProfiles 를 사용하여, 변경할 수 있다.
profile 이 변경되는 경우, 설정 정보도 profile 에 맞게 변경되어 context 가 생성된다.
@SpringBootTest
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
@ActiveProfiles("local") // dev, prod 등으로 변경할 수 있다.
class IntegrationTest
구성정보 바꾸기 - @Configuration , @TestConfiguration
해당 부분도 2편에서 더 자세하게 다루려고 한다.
https://pius712.tistory.com/36
환경변수 바꾸기 - @TestPropertySource
application properties를 테스트 전용 값으로 바꿔칠 수 있다.
@TestPropertySource(properties = ["datasource.connection-pool=3"])
class TestMockTest(
private val testService: TestService,
):IntegrationTest() {
@Test
fun test() {
testService.test()
}
}
'스프링부트' 카테고리의 다른 글
JPA 1차캐시의 동작 방식 (0) | 2024.07.28 |
---|---|
스프링부트 테스트(2) - configuration 과 property (1) | 2024.07.23 |
AOP 활용 (feat. jpa 호출 로깅) (0) | 2024.06.06 |
스프링 AOP - 톺아보기 (1) | 2024.06.06 |
나는 테스트에서 @Transactional 붙이지 않겠다.. (feat. 동시성 삽질기) (0) | 2024.05.02 |