본문 바로가기
Java & Kotlin/Kotlin

Kotest Runtime Detection 설정으로 테스트 실행 시간 개선하기

by devson 2025. 7. 5.

(Kotest 5.9.x 버전 기준의 내용입니다)

 

Kotest는 병렬 처리를 위한 parallelism 값이나 extension과 같은 설정을 AbstractProjectConfig class를 통해 할 수 있다.

import io.kotest.core.config.AbstractProjectConfig

object MyKotestProjectConfig : AbstractProjectConfig() {
    override val parallelism = 3
}

https://kotest.io/docs/framework/project-config.html

 

Project Level Config | Kotest

Kotest is flexible and has many ways to configure tests, such as configuring the order of tests inside a spec, or how

kotest.io

 

그리고 테스트에 대해 Lifecycle listener를 전역으로 적용할 수 있는데 이때 @AutoScan을 사용하기도 한다.

import io.kotest.core.annotation.AutoScan
import io.kotest.core.listeners.AfterProjectListener
import io.kotest.core.listeners.BeforeProjectListener

@AutoScan
object MyProjectListener : BeforeProjectListener, AfterProjectListener {
  override suspend fun beforeProject() {
    println("Project starting")
  }
  override suspend fun afterProject() {
    println("Project complete")
  }
}

https://kotest.io/docs/framework/extensions/extensions-introduction.html#how-to-use

 

Introduction to Extensions | Kotest

Extensions are reusable lifecycle hooks. In fact, lifecycle hooks are themselves represented internally as instances

kotest.io

 

기본적으로 이러한 설정 클래스는 따로 path를 지정하지 않아도 적용되는데,

이는 Kotest가 테스트를 실행하면서 해당 클래스가 있는지 scan을 하기 때문이다.

 

하지만 테스트 실행 시에 매번 설정을 scan 하기 때문에 설정 클래스 파일만 잘 관리하면 되지만 이로인해서 테스트 실행 시간이 늘어날 수 있다.

또한 테스트를 실행하면 다음과 같이 Warning 로그가 뜨는 것을 볼 수 있다.

 

컴퓨팅 파워가 넉넉한 로컬 개발 환경에서는 테스트 시간이 늘어나봤자 경험적으로 ~10초 정도이지만

그렇지 못한 CI 환경(특히 기본 Github Actions 컴퓨팅 환경)에서는 분단위로 테스트 시간이 늘어나게되어 개발 cycle이 조금씩 지연되는 원인이 되기도 한다.

 

실제로 나의 경우 CI 환경에서 설정 @AutoScan  달린 설정 scan으로 인해 1분 정도의 시간이 소모되었다.

 

이번 포스팅에서는 설정을 scan하는 runtime detection 설정을 변경하여 테스트 실행 시간을 개선하고 그 과정에서의 트러블 슈팅 경험을 정리하도록 한다.

 


 

테스트 실행 시 설정을 scan하는 runtime detection을 끄는 설정은 아래와 같고 기본적으로 모두 false 상태이다. (5.9.x 버전 기준)

  • kotest.framework.classpath.scanning.config.disable
  • kotest.framework.classpath.scanning.autoscan.disable

 

이 설정을 모두 true로 하고자한다면 src/test/resources 경로에 kotest.properties 파일을 생성하여 설정을 추가해주면된다.

kotest.framework.classpath.scanning.config.disable=true
kotest.framework.classpath.scanning.autoscan.disable=true

 

 

설정에 따른 테스트 실행 시간을 확인하기 위해 나의 CI 환경에서 옵션을 추가해가면서 확인을 해보았다.

그 결과는 아래와 같다.

 

 

trial default config scanning.autoscan.disable=true scanning.config.disable=true
scanning.autoscan.disable=true
1st 3m 34s 2m 54s 2m 18s
2nd 3m 24s 2m 56s 2m 17s
3rd 3m 21s 2m 51s 2m 18s

 

runtime detection 설정을 끄니 로컬에서는 수 초의 차이밖에 보이지 않았지만,

CI 환경에서는 1분 이상의 드라마틱한 개선이 이뤄지는 것을 확인할 수 있었다.

 

 

하지만 Spring framework를 사용할 때 통합 테스트를 위해 Kotest Spring extension을 사용하고

Spec class의 생성자에 Spring bean을 주입받아서 사용한다면 위 설정을 했을 때 오류가 날 수 있다.

io.kotest.engine.spec.SpecInstantiationException: Could not create instance of class xx.XXTest. Specs must have a public zero-arg constructor.

 

이는 runtime detection 기능을 모두 껐기 때문에  생기는 문제로 document에도 설명하고 있다.

https://kotest.io/docs/extensions/spring.html#constructor-injection

 

그렇기 때문에 추가적으로 AbstractProjectConfig 구현체를 만들어 Spring과 관련된 extension을 등록해줘야한다.

import io.kotest.core.config.AbstractProjectConfig
import io.kotest.core.extensions.Extension
import io.kotest.extensions.spring.SpringAutowireConstructorExtension
import io.kotest.extensions.spring.SpringExtension

object KotestProjectConfiguration : AbstractProjectConfig() {
    override fun extensions(): List<Extension> {
        return listOf(
            SpringExtension, // Integrate Spring with Kotest
            SpringAutowireConstructorExtension, // Allow Spring bean constructor injection for Kotest Spec classes
        )
    }
}

 

그리고 해당 설정을 kotest.proprerties에서 사용하도록 추가해줘야 정상적으로 위 AbstractProjectConfig 구현체가 설정으로써 등록이 된다.

kotest.framework.classpath.scanning.config.disable=true
kotest.framework.classpath.scanning.autoscan.disable=true
kotest.framework.config.fqn=path.to.KotestProjectConfiguration

 

이렇게 설정을 해주면 Kotest Spec class에서 Spring bean을 주입할 수 있게된다.

댓글