Kotestテスト順序制御(Ordering)

KotestでのOrderingは、テスト実行の順序を制御する機能である。特定の順序でテストを実行したい場合や、特定条件に応じてテストをフィルタリングして実行する場合に便利である。

テスト順序制御

Kotestはさまざまな方法でテスト順序を制御できる。Ordering機能を使ってテストを調整することで、テスト間の依存関係や相互作用による問題を防ぎ、より予測可能なテスト実行環境を構成できる。

KotestでOrderingを制御する方法は大きく2つある。

  1. Spec Ordering: 特定のテストSpec、またはテストクラス内部でテストの実行順序を調整する方法である。これにより、特定Spec内のテストの実行順序を調整できる。
  2. Test Ordering: 特定のテストSpec内のテスト、または特定のテストSpec間の実行順序を調整する方法である。これにより、複数のテストSpec間の実行順序を調整できる。

Spec Ordering

デフォルトではSpecクラスの順序は定義されていない。つまり、検索メカニズムがどの順序で見つけるかにより、基本的にはランダムである。

順序がなくても大きな支障はないが、Spec上の実行順序を制御する必要がある場合は、プロジェクト構成で順序を指定する。

class OrderingConfig: AbstractProjectConfig() {
    override val specExecutionOrder = SpecExecutionOrder.Undefined
}

SpecExecutionOrderにはいくつかのオプションがある。

  • Undefined: デフォルト値である。順序は定義されず、ランタイムで発見された順に実行される。たとえば、JVMクラスパス検索、またはJavaScriptファイルに表示された順に実行される。
  • Lexicographic: 辞書順にソートされる。
  • Random: 明示的にランダムな順序でSpecが実行される。
  • Annotated: クラスに追加された@Orderアノテーションを使い、入力値が最も低いものから先に実行される。このアノテーションがない場合は「最後」と見なされる。このオプションはJVMでのみ動作する。同じ値は任意の順序で実行される。

Lexicographicで順序指定

次の例は辞書順で実行されるよう定義されている。

package com.devkuma.kotest.tutorial.ordering

import io.kotest.core.config.AbstractProjectConfig
import io.kotest.core.spec.SpecExecutionOrder
import io.kotest.core.spec.style.FunSpec

class LexicographicConfig: AbstractProjectConfig() {
    override val specExecutionOrder = SpecExecutionOrder.Lexicographic
}

class AlphaTest : FunSpec({
    test("alpha") {
        println("AlphaTest")
    }
})

class BetaTest : FunSpec({
    test("beta") {
        println("BetaTest")
    }
})

class GammaTest : FunSpec({
    test("gamma") {
        println("GammaTest")
    }
})


class DeltaTest : FunSpec({
    test("delta") {
        println("DeltaTest")
    }
})

テストを実行すると次のように出力される。

AlphaTest
BetaTest
DeltaTest
GammaTest

アルファベット順であるAlphaTestBetaTestDeltaTestGammaTestの順に出力されることを確認できる。

Annotatedで順序指定

次の例は@Orderでアノテーション指定されている。

package com.devkuma.kotest.tutorial.ordering

import io.kotest.core.config.AbstractProjectConfig
import io.kotest.core.spec.Order
import io.kotest.core.spec.SpecExecutionOrder
import io.kotest.core.spec.style.FunSpec

class AnnotatedConfig: AbstractProjectConfig() {
    override val specExecutionOrder = SpecExecutionOrder.Annotated
}

@Order(1)
class FooTest : FunSpec({
    test("foo") {
        println("FooTest")
    }
})

@Order(0)
class BarTest: FunSpec({
    test("bar") {
        println("BarTest")
    }
})

@Order(1)
class FarTest : FunSpec({
    test("far") {
        println("FarTest")
    }
})

class BooTest : FunSpec({
    test("boo") {
        println("BooTest")
    }
})

テストを実行すると次のように出力される。

BarTest
FarTest
FooTest
BooTest

Orderが最も低いBarTestが最初に実行される。FarTestFooTestは次に低い値なのでその後に実行されるが、どちらも値が1のため、その間の順序は定義されない。最後に、BooTestはアノテーションがないため最後に実行される。

Test Ordering

Specに従って複数のテストを実行するとき、実行方法には一定の順序がある。

デフォルトでは順次(sequential)順序、つまりテストがSpecに定義された順序が使われるが、ランダム(random)順序または辞書的(lexicographic)順序で実行されるよう構成することもできる。

この設定は、SpecまたはProjectConfigtestCaseOrder関数を再定義して構成できる。両方が存在する場合、Specの設定が優先される。

順次(Sequential)順序

以下の例では、テストは定義された順序どおりに実行される。

package com.devkuma.kotest.tutorial.ordering.testordering

import io.kotest.core.spec.style.StringSpec
import io.kotest.core.test.TestCaseOrder

class SequentialSpecTest : StringSpec() {

    override fun testCaseOrder(): TestCaseOrder = TestCaseOrder.Sequential

    init {
        "foo" {
            // I run first as I'm defined first
            println("foo")
        }

        "bar" {
            // I run second as I'm defined second
            println("bar")
        }
    }
}

ランダム(Random)順序

以下の例では、テストはランダム順序で実行される。

package com.devkuma.kotest.tutorial.ordering.testordering

import io.kotest.core.spec.style.StringSpec
import io.kotest.core.test.TestCaseOrder

class RandomSpecTest : StringSpec() {

    override fun testCaseOrder(): TestCaseOrder = TestCaseOrder.Random

    init {
        "foo" {
            // This test may run first or second
            println("foo")
        }

        "bar" {
            // This test may run first or second
            println("bar")
        }
    }
}

テストを実行すると次のように出力されることがある。

foo
bar

また、次のように出力されることもある。

bar
foo

辞書的(Lexicographic)順序

以下の例では、テストは辞書的順序で実行される。

package com.devkuma.kotest.tutorial.ordering.testordering

import io.kotest.core.spec.style.StringSpec
import io.kotest.core.test.TestCaseOrder

class LexicographicSpecTest : StringSpec() {

    override fun testCaseOrder(): TestCaseOrder = TestCaseOrder.Lexicographic

    init {

        "beta" {
            // I run second as gamma < beta < alpha
            println("beta")
        }

        "alpha" {
            // I run first as gamma < beta < alpha
            println("alpha")
        }

        "gamma" {
            // I run third as gamma < beta < alpha
            println("gamma")
        }
    }
}

テストを実行すると次のように出力される。

alpha
beta
gamma

参照