Kotest 격리 모드(Isolation Modes)

격리 모드(Isolation Modes)의 설정으로 테스트 엔진이 테스트 케이스에 대한 스펙 인스턴스를 생성하는 방법을 제어할 수 있다. 즉, 테스트 케이스마다 테스트 인스턴스를 어떻게 생성할지를 결정한다.

Isolation Modes

Isolation Modes의 설정을 어떻게 하냐에 따라 테스트 성능을 차이가 발생할 수 있고, 인스턴스 재사용으로 인한 테스트 실패도 방지할 있게 때문에 반듯이 알아두어야 한다.

Isolation Mode를 설정하는 방법은 3가지가 있다. IsolationMode라는 enum으로 제어할 수 있으며 InstancePerTest, SingleInstance, InstancePerLeaf가 있다. 상황에 맞게 원하는 방식대로 사용하면 된다.

테스트 간에 공유되는 상태를 초기화할 수 있도록 테스트가 새 인스턴스 내에서 실행되도록 하려면 격리 모드를 변경하면 된다.

이 작업은 다음과 같은 DSL을 사용하여 isolationMode에 값을 할당하여 수행할 수 있다:

class MyTest : WordSpec({
    isolationMode = IsolationMode.SingleInstance
    
    // tests here
})

또는 fun isolationMode(): IsolationMode 함수를 오버라이드 설정할 수 있다:

class MyTest : WordSpec() {
    override fun isolationMode() = IsolationMode.SingleInstance

    init {
        // tests here
    }
}

SingleInstance

디폴트 격리 모드인 SingleInstance은 Spec 클래스의 하나의 인스턴스가 생성된 다음 모든 테스트가 완료될 때까지 각 테스트 케이스가 차례로 실행되는 방식이다.

이 모드는 모든 테스트 간의 상태 공유를 허용하므로 테스트 간의 의존성을 유지하고자 할 때 유용하다.

package com.devkuma.kotest.tutorial.isolation

import io.kotest.core.spec.style.WordSpec
import java.util.*

class SingleInstanceExample : WordSpec({

    val id = UUID.randomUUID()

    "a" should {
        println("a: $id")
        "b" {
            println("b: $id")
        }
        "c" {
            println("c: $id")
        }
    }
})

다음은 예제를 실행한 결과이다:

a: 3823310d-43d3-47a0-953b-fa3afeb39307
b: 3823310d-43d3-47a0-953b-fa3afeb39307
c: 3823310d-43d3-47a0-953b-fa3afeb39307

실행 결과는 모든 테스트에 동일한 인스턴스가 사용되므로 동일한 ID가 세 번 출력된다.

InstancePerTest

다음 IsolationMode.InstancePerTest 모드는 내부 콘텍스트를 포함하여 모든 테스트 케이스에 대해 새 Spec이 생성된다. 즉, 외부 콘텍스트는 Spec의 자체 인스턴스에서 “독립 실행형(stand alone)” 테스트로 실행된다.

예제를 통해 이를 명확히 알 수 있다.

package com.devkuma.kotest.tutorial.isolation

import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.WordSpec
import java.util.*

class InstancePerTestExample : WordSpec() {

    override fun isolationMode(): IsolationMode = IsolationMode.InstancePerTest

    val id = UUID.randomUUID()

    init {
        "a" should {
            println("a: $id")
            "b" {
                println("b: $id")
            }
            "c" {
                println("c: $id")
            }
        }
    }
}

다음은 예제를 실행한 결과이다:

a: 19c3b379-a688-428c-b3e8-8cb507bdf083
a: ffaff5f6-5c6a-41a9-98b9-52f9ca134dfa
b: ffaff5f6-5c6a-41a9-98b9-52f9ca134dfa
a: 08e42544-def7-4859-8b2b-34bb50fe83b0
c: 08e42544-def7-4859-8b2b-34bb50fe83b0

외부 콘텍스트(테스트 “a”)가 먼저 실행되고, 그런 다음(테스트 “b”)에 대해 다시 실행되고, (테스트 “c”)에 대해 다시 실행된다. Spec 클래스의 깨끗한 인스턴스에서 매번, 변수를 재사용하고자 할 때 매우 유용하다.

InstancePerLeaf

IsolationMode.InstancePerLeaf 모드는 내부 컨텍스트를 포함해서 모든 테스트 케이스에 대해 새로운 인스턴스를 생성하여 독립적으로 실행한다. 이 모드는 테스트 케이스 간의 상태 공유를 방지하여 테스트의 독립성을 보장한다. 그러나 그만큼 자원을 많이 소모하는 점을 염두해 두고 이 모드를 사용해야 한다.

예제를 통해 이를 확인하도록 한다.

package com.devkuma.kotest.tutorial.isolation

import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.WordSpec
import java.util.*

class InstancePerLeafExample : WordSpec() {

    override fun isolationMode(): IsolationMode = IsolationMode.InstancePerLeaf

    private val id = UUID.randomUUID()

    init {
        "a" should {
            println("a: $id")
            "b" {
                println("b: $id")
            }
            "c" {
                println("c: $id")
            }
        }
    }
}

다음은 예제를 실행한 결과이다:

a: 71830c57-6ee0-4b1f-8c32-812defac2b1e
b: 71830c57-6ee0-4b1f-8c32-812defac2b1e
a: 480ee65a-df4c-4a78-ac80-b6ae2c85ee20
c: 480ee65a-df4c-4a78-ac80-b6ae2c85ee20

“a” 테스트가 먼저 실행되고 동일한 인스턴스에서 “b” 테스트가 실행된다. 그런 다음 새 Spec이 생성되고 테스트 “a"가 다시 실행된 다음 테스트 “c"가 실행된다.

Global Isolation Mode

시스템 속성을 통해 전역적으로 Isolation Mode를 설정할 수도 있다.

object GlobalIsolationConfiguration : AbstractProjectConfig() {
    override val isolationMode = IsolationMode.SingleInstance
}

참고




최종 수정 : 2024-04-21