Kotest分離モード(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クラスのインスタンスを1つ生成した後、すべてのテストが完了するまで各テストケースを順番に実行する方式である。
このモードではすべてのテスト間で状態を共有できるため、テスト間の依存関係を維持したい場合に便利である。
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が3回出力される。
InstancePerTest
次のIsolationMode.InstancePerTestモードでは、内部コンテキストを含むすべてのテストケースに対して新しいSpecが生成される。
つまり、外側のコンテキストはSpec自身のインスタンスでスタンドアロンのテストとして実行される。
例を見ると分かりやすい。
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
}