Docker를 통해서 TestContainer를 사용 중, 테스트 데이터를 집어넣는 스크립트를 실행하는 코드를 작성했다. 문제는 전체 테스트를 실행하면,
상위 클래스에 @TestInstance(TestInstance.Lifecycle.PER_CLASS) 와 @BeforeAll 를 사용해도, 테스트 클래스마다 인스턴스가 새로 생성되며, 상속받는 부모 클래스의 메서드를 한 번 씩 호출한다는 점. 그래서 매번 테스트 클래스마다 스크립트를 실행하는 코드를 계속 호출하므로 속도가 느리다. 방법을 찾던 중, Junit 확장 인터페이스 중 BeforeAllCallback이 눈에 띄었다.
class TestDataSetup : BeforeAllCallback, ExtensionContext.Store.CloseableResource {
private var dataSource: DataSource? = null
private var s3Mock:S3Mock? = null
private val log = KotlinLogging.logger { }
override fun beforeAll(extensionContext: ExtensionContext) {
synchronized(TestDataSetup::class.java) {
if (!started) {
started = true
// get the dataSource bean from the spring context
val springContext: ApplicationContext = SpringExtension.getApplicationContext(extensionContext)
dataSource = springContext.getBean(DataSource::class.java)
s3Mock = springContext.getBean(S3Mock::class.java)
try {
s3Mock!!.start()
dataSource!!.connection.use { conn ->
log.info("TEST!!!!!!!!!!!@@@@@@@=>${conn.metaData.url}")
ScriptUtils.executeSqlScript(conn, ClassPathResource("/initData/init.sql"))
}
} catch (e: Exception) {
e.printStackTrace()
}
// register a callback hook for when the root test context is shut down
extensionContext
.getRoot()
.getStore(ExtensionContext.Namespace.GLOBAL)
.put("TestDataSetup-started", this)
}
}
}
override fun close() {
synchronized(TestDataSetup::class.java) {
log.info("Tear down Amazon")
s3Mock?.stop()
}
}
companion object {
private var started = false
}
}
병렬 처리에 문제가 생길 수 있으므로, synchronized를 붙여주는 게 좋다고 한다.
그리고 한번만 실행하고 싶은 모든 테스트 클래스의 부모 클래스에,
@SpringBootTest(
properties = ["spring.config.location=classpath:/application-test.yml" , "spring.profiles.active=test"]
)
@ExtendWith(TestDataSetup::class)
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class SpringTestSupport() {
}
그리고 스크립트를 실행하고 싶은 모든 테스트 클래스를 상속시켜준다.
@Transactional
class AuthApiTest(
) : SpringWebTestSupport() {
}
@Transactional
class MemberApiTest(
) : SpringWebTestSupport() {
}
https://stackoverflow.com/questions/43282798/in-junit-5-how-to-run-code-before-all-tests
https://stackoverflow.com/questions/56904620/junit-5-inject-spring-components-to-extension-beforeallcallback-afterallcall/62504238#62504238