Kotestテスト順序制御(Ordering)
テスト順序制御
Kotestはさまざまな方法でテスト順序を制御できる。Ordering機能を使ってテストを調整することで、テスト間の依存関係や相互作用による問題を防ぎ、より予測可能なテスト実行環境を構成できる。
KotestでOrderingを制御する方法は大きく2つある。
- Spec Ordering: 特定のテストSpec、またはテストクラス内部でテストの実行順序を調整する方法である。これにより、特定Spec内のテストの実行順序を調整できる。
- 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
アルファベット順であるAlphaTest、BetaTest、DeltaTest、GammaTestの順に出力されることを確認できる。
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が最初に実行される。FarTestとFooTestは次に低い値なのでその後に実行されるが、どちらも値が1のため、その間の順序は定義されない。最後に、BooTestはアノテーションがないため最後に実行される。
Test Ordering
Specに従って複数のテストを実行するとき、実行方法には一定の順序がある。
デフォルトでは順次(sequential)順序、つまりテストがSpecに定義された順序が使われるが、ランダム(random)順序または辞書的(lexicographic)順序で実行されるよう構成することもできる。
この設定は、SpecまたはProjectConfigでtestCaseOrder関数を再定義して構成できる。両方が存在する場合、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