Kotest 타임아웃(timeouts)

테스트에 호출 시간 제한을 두고 테스트를 하는 방법에 대해서 설명한다.

테스트 시간 초과

Kotest는 두 가지 유형의 테스트 시간 제한을 지원한다. 첫 번째는 테스트의 모든 호출에 대한 전체 시간이다. 이를 타임아웃이라고 한다. 두 번째는 테스트의 개별 실행당이며, 이를 호출 시간 제한이라고 한다.

테스트 시간 제한

테스트 시간 제한을 설정하려면 테스트 구성을 사용하면 된다:

class TimeoutTest : FunSpec({
   test("this test will timeout quickly!").config(timeout = 100.milliseconds) {
      // test here
   }
})

또는 사양 파일의 모든 테스트에 테스트 시간 제한을 적용할 수도 있다:

class TimeoutTest : FunSpec({

   timeout = 100.milliseconds

   test("this test will timeout quickly!") {
      // test here
   }

   test("so will this one!") {
      // test here
   }
})

호출 시간 초과

Kotest는 테스트를 여러 번 호출하도록 구성할 수 있다. 예를 들어:

class TimeoutTest : DescribeSpec({

   describe("my test context") {
        it("run me three times").config(invocations = 3) {
            // this test will be invoked three times
        }
   }

})

그런 다음 invocationTimeout 속성을 사용하여 호출당 타임아웃을 적용할 수 있다.

class TimeoutTest : DescribeSpec({

   describe("my test context") {
        it("run me three times").config(invocations = 3, invocationTimeout = 60.milliseconds) {
            // this test will be invoked three times and each has a timeout of 60 milliseconds
        }
   }

})

이전 예제에서 각 호출은 60밀리초 이내에 완료되어야 한다. 이를 전체 테스트 시간 초과와 결합할 수 있다:

class TimeoutTest : DescribeSpec({

   describe("my test context") {
        it("run me three times").config(timeout = 100.milliseconds, invocations = 3, invocationTimeout = 60.milliseconds) {
            // this test will be invoked three times
        }
   }

})

여기서는 세 가지 테스트가 모두 100밀리초 이내에 완료되도록 하되, 특정 호출이 최대 60밀리초까지 연장될 수 있도록 한다.

테스트 타임아웃과 마찬가지로 사양 수준에서 호출 타임아웃을 적용할 수 있다:

class TimeoutTest : FunSpec({

   invocationTimeout = 25.milliseconds

   test("foo") {
      // test here
   }

   test("bar") {
      // test here
   }
})

프로젝트 전체 설정

프로젝트 구성을 사용하여 모듈의 모든 테스트에 테스트 및/또는 호출 시간 제한을 적용할 수 있다.

object ProjectConfig : AbstractProjectConfig {
    override val timeout = 100.milliseconds
    override val invocationTimeout = 33.milliseconds
}

이러한 값은 사양 또는 테스트 수준에서 재정의하지 않는 한 적용된다.

시스템 속성

테스트 시간 제한과 호출 시간 제한은 모두 시스템 속성을 사용하여 설정할 수 있으며, 밀리초 단위로 값을 지정할 수 있다.

  • kotest.framework.timeout은 결합된 테스트 시간 제한을 설정한다.
  • kotest.framework.invocation.timeout은 호출 테스트 시간 제한을 설정한다.

프로젝트 시간 초과

Kotest는 프로젝트 레벨 타임아웃을 지원한다. 이 타임아웃은 모듈의 모든 테스트에 적용되며 모듈의 모든 사양/테스트의 설정/해체 시간을 포함한다.

이를 활성화하려면 ProjectConfig를 사용하면 된다.

class ProjectConfig : AbstractProjectConfig() {
  override val projectTimeout: Duration = 10.minutes
}

위 예제에서는 프로젝트 타임아웃을 10분으로 지정했다. 모든 사양과 테스트는 10분 이내에 완료되어야 하며, 그렇지 않으면 빌드가 실패한다.

테스트 차단

테스트에서 시간 초과를 지정할 때 Kotest는 Kotlin 코루틴 라이브러리가 제공하는 withTimeout 코루틴 함수를 사용한다. 이러한 타임아웃은 본질적으로 협력적이며, 코루틴이 일시 중단, 재개 또는 yield를 호출할 때 타임아웃이 감지된다.

그러나 차단 코드를 실행할 때는 스레드가 차단되므로 협력적 접근 방식이 작동하지 않는다. 이 시나리오에서는 Thread.interrupt 또는 이와 유사한 것을 사용하여 스레드를 중단하는 것으로 되돌려야 한다. 이 중단이 안전하게 작동하려면 전용 스레드에서 테스트를 실행해야 한다.

따라서 특정 테스트가 중단에 안전하게 사용할 수 있는 전용 스레드에서 실행되기를 원한다는 것을 Kotest에 알리는 것은 사용자의 몫이다. 테스트 구성에서 차단 테스트 플래그를 활성화하면 된다.

예를 들어:

class MyBlockingTest : FunSpec() {
  init {

    test("interrupt me!").config(blockingTest = true, timeout = 10.seconds) {
       Thread.sleep(100000000)
    }

    test("uses suspension").config(timeout = 10.seconds) {
      delay(100000000)
    }
  }
}

위의 예에서 첫 번째 테스트는 스레드 차단 연산을 사용하기 때문에 차단 테스트 플래그가 필요하다. 두 번째 테스트는 일시 중단 가능한 연산을 사용하기 때문에 필요하지 않는다.


참조




최종 수정 : 2024-04-21