Kotest Spring 확장(SpringExtension)
TIP
문서를 읽는 것보다 예제를 보고 싶으시다면 여기 스프링 웹플럭스를 사용하는 샘플 프로젝트를 참고 바란다.Spring Extension
의존성 추가
이 확장 기능을 사용하려면 테스트 컴파일 경로에 io.kotest.extensions:kotest-extensions-spring
모듈을 추가해야 한다. 최신 버전은 maven central에서 확인할 수 있다.
먼저 Spring에 kotest를 사용하려면 아래 의존성을 추가해야 한다.
testImplementation("io.kotest.extensions:kotest-extensions-spring:1.0.0")
참고: maven 그룹 ID는 핵심 테스트 프레임워크(
io.kotest.extensions
)와 다르다.
Configuration
모든 테스트에 대해 SpringExtension을 적용하려면 글로벌 설정을 통해서 설정이 가능하다.
class GlobalProjectConfig : AbstractProjectConfig() {
override fun extensions() = listOf(SpringExtension)
}
Spring 확장을 사용하려면 모든 테스트 클래스 또는 테스트 클래스별로 활성화해야 한다.
전역으로 활성화하려면 프로젝트 구성에서 SpringExtension
을 등록해야 한다:
class ProjectConfig : AbstractProjectConfig() {
override fun extensions() = listOf(SpringExtension)
}
때로는 SpringExtension
을 전역으로 활성화하지 않고 테스트를 사용하고 싶을 수도 있다. 이런 경우 글로벌 설정을 하지 않고 SpringExtension을 사용하는 테스트 클래스에서만 extensions를 설정해서 사용할 수도 있다.
테스트 클래스별로 활성화하는 방법은 아래와 같다:
class SpringTest : FunSpec() {
override fun extensions() = listOf(SpringExtension)
}
Spring에 사용할 구성 클래스를 알려주려면 Spec 클래스에 @ContextConfiguration
어노테이션을 추가해야 한다. 이 어노테이션은 Spring @Configuration
어노테이션으로 어노테이션된 클래스를 가리켜야 한다. 또는 @ActiveProfiles
를 사용하여 특정 애플리케이션 컨텍스트 파일을 가리킬 수 있다.
NOTE
Kotest 4.3 및 이전 버전에서는 Spring 확장을SpringListener
라고 불렀다. 이 확장은 이제 더 이상 사용되지 않고 SpringExtension
으로 대체되었다. 사용법은 동일하지만 SpringExtension
에 더 많은 기능이 제공된다.
생성자 주입
생성자 주입의 경우, 자동 스캔이 활성화되어 있다고 가정하고 스프링 모듈이 빌드에 추가될 때 Kotest는 SpringAutowireConstructorExtension
을 자동으로 등록한다(프로젝트 구성 참조). 자동 스캔이 비활성화되어 있으면 프로젝트 구성에서 수동으로 확장자를 로드해야 한다.
이 확장은 Spec 인스턴스를 생성하기 위한 각 호출을 가로채고 기본 생성자에서 선언된 Bean을 자동 연결한다.
다음 예제는 기본 생성자에 UserService
라는 서비스가 필요한 테스트 클래스이다. 이 서비스 클래스는 @Component
로 어노테이션된 일반 스프링 빈이다.
@ContextConfiguration(classes = [(Components::class)])
class SpringAutowiredConstructorTest(service: UserService) : WordSpec() {
init {
"SpringExtension" should {
"have autowired the service" {
service.repository.findUser().name shouldBe "system_user"
}
}
}
}
@SpringBootTest
를 사용하는 방법도 있다:
@SpringBootTest(classes = [FooService::class])
class SpringTest(fooService: FooService) : FunSpec() {
override fun extensions() = listOf(SpringExtension)
init {
test("getFoo test") {
val actual = fooService.getFoo()
actual shouldBe Foo("id", "foo")
}
}
}
@Service
class FooService {
fun getFoo(): Foo {
return Foo("id", "foo")
}
}
data class Foo(
val id: String,
val title: String,
)
테스트 컨텍스트
Spring 확장은 테스트가 실행되는 코루틴 컨텍스트를 통해 TestContextManager
를 사용할 수 있게 해준다. 이 인스턴스에 대한 핸들은 testContextManager()
확장 메서드를 통해 얻을 수 있다.
이를 통해 Spring이 사용 중인 테스트 컨텍스트를 가져올 수 있다.
class MySpec(service: UserService) : WordSpec() {
init {
"SpringExtension" should {
"provide the test context manager" {
println("The context is " + testContextManager().testContext)
}
}
}
}
테스트 메서드 콜백
Spring에는 테스트가 메서드라는 개념에 기반한 beforeTestMethod
와 같은 다양한 테스트 콜백이 있다. 이 가정은 JUnit과 같은 레거시 테스트 프레임워크에는 적합하지만 테스트가 함수인 Kotest와 같은 최신 테스트 프레임워크에는 적용되지 않는다.
따라서 중첩된 스펙 스타일을 사용하는 경우 테스트 메서드 콜백이 실행되는 시기를 사용자 지정할 수 있다. 기본적으로 이것은 리프 노드에 있다. SpringTestLifecycleMode 인수를 확장에 전달하여 루트 노드에서 실행되도록 설정할 수 있다:
class ProjectConfig : AbstractProjectConfig() {
override fun extensions() = listOf(SpringTestExtension(SpringTestLifecycleMode.Root))
}
파이널 클래스
파이널 클래스를 사용할 때 Kotest로부터 다음과 같은 경고를 받을 수 있다:
Using SpringListener on a final class. If any Spring annotation fails to work, try making this class open
원하는 경우에는 시스템 속성 kotest.listener.spring.ignore.warning
을 true
로 설정하여 이 경고를 비활성화할 수 있다.