Kotest Isolation Modes
Isolation Modes
Depending on how you configure Isolation Modes, test performance can differ, and you can also prevent test failures caused by instance reuse. For that reason, this is something you should understand clearly.
There are three ways to configure Isolation Mode. It is controlled by the IsolationMode enum, which provides InstancePerTest, SingleInstance, and InstancePerLeaf. Use whichever mode fits your situation.
If you want tests to run in new instances so that state shared between tests can be initialized, change the isolation mode.
You can do this by assigning a value to isolationMode with the following DSL:
class MyTest : WordSpec({
isolationMode = IsolationMode.SingleInstance
// tests here
})
Or you can override the fun isolationMode(): IsolationMode function:
class MyTest : WordSpec() {
override fun isolationMode() = IsolationMode.SingleInstance
init {
// tests here
}
}
SingleInstance
SingleInstance, the default isolation mode, creates one instance of the Spec class and then runs each test case in order until all tests are complete.
This mode allows state to be shared between all tests, so it is useful when you want to keep dependencies between tests.
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")
}
}
})
The following is the result of running the example:
a: 3823310d-43d3-47a0-953b-fa3afeb39307
b: 3823310d-43d3-47a0-953b-fa3afeb39307
c: 3823310d-43d3-47a0-953b-fa3afeb39307
The same ID is printed three times because the same instance is used for every test.
InstancePerTest
The next mode, IsolationMode.InstancePerTest, creates a new Spec for every test case, including internal contexts.
In other words, the outer context is executed as a standalone test in its own Spec instance.
The example makes this clear.
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")
}
}
}
}
The following is the result of running the example:
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
The outer context, test "a", runs first, then runs again for test "b", and again for test "c".
This is very useful when you want to reuse variables each time from a clean instance of the Spec class.
InstancePerLeaf
IsolationMode.InstancePerLeaf creates a new instance for every test case, including internal contexts, and runs them independently. This mode prevents state from being shared between test cases and guarantees test independence. However, keep in mind that it consumes more resources.
You can confirm this with the following example.
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")
}
}
}
}
The following is the result of running the example:
a: 71830c57-6ee0-4b1f-8c32-812defac2b1e
b: 71830c57-6ee0-4b1f-8c32-812defac2b1e
a: 480ee65a-df4c-4a78-ac80-b6ae2c85ee20
c: 480ee65a-df4c-4a78-ac80-b6ae2c85ee20
Test "a" runs first, and test "b" runs in the same instance.
Then a new Spec is created, test "a" runs again, and then test "c" runs.
Global Isolation Mode
You can also configure Isolation Mode globally through a system property.
object GlobalIsolationConfiguration : AbstractProjectConfig() {
override val isolationMode = IsolationMode.SingleInstance
}