kotest icon indicating copy to clipboard operation
kotest copied to clipboard

`IsolationMode.InstancePerTest` not working for native tests

Open filipegeric opened this issue 2 years ago • 7 comments

Kotest version: 5.5.1

In a multiplatform project when running nativeTest IsolationMode.InstancePerTest is not working. Setting it in the class doesn't work:

import io.kotest.core.spec.DisplayName
import io.kotest.core.spec.IsolationMode
import io.kotest.core.spec.style.StringSpec
import io.kotest.matchers.shouldBe

@DisplayName("Running an example")
class ExampleTests : StringSpec() {
    var a = 0

    override fun isolationMode() = IsolationMode.InstancePerTest

    init {
        "should be 1 after 1 increment" {
            a++
            a shouldBe 1
        }

        "should be 2 after 2 increments" {
            a++
            a++
            a shouldBe 2
        }
    }

}

or setting it as a system property in build.gradle.kts:

tasks.withType<Test> {
    systemProperty("kotest.framework.isolation.mode", "InstancePerTest")
}

The result of running ./gradlew nativeTest is the following (The error message is not descriptive):

> Task :nativeTest FAILED

ExampleTests.should be 2 after 2 increments FAILED
    io.kotest.assertions.AssertionFailedError at null:-1

2 tests completed, 1 failed

FAILURE: Build failed with an exception.

filipegeric avatar Feb 16 '23 10:02 filipegeric

@Kantis, any chance this could be prioritized?

We rely on isolated tests heavily and currently have to manually reset implementations of our fake dependencies in each beforeTest. We would love to apply isolation mode globally so that we can drop all of that bespoke configuration in favor of isolation mode, but currently blocked by it not working on iOS.

kirillzh avatar Jul 24 '23 18:07 kirillzh

Looks like this is simply not implemented.

The JVM executor will define a runner based on the isolation mode, as seen here

The native counterpart resides here.

Trying to move the SpecRunners to commonMain shows that they rely on some JVM-only classes, namely:

I'm not very familiar with what's available on multiplatform. Is there anything we could use to replace these classes easily?

Kantis avatar Jul 25 '23 21:07 Kantis

Thank you for context @Kantis, this is helpful!

  • For atomic operations - https://github.com/Kotlin/kotlinx-atomicfu
  • For concurrent mutable map - https://github.com/touchlab/Stately/blob/main/stately-concurrent-collections/src/commonMain/kotlin/co/touchlab/stately/collections/ConcurrentMutableMap.kt
  • For PriorityQueue, as far as I know there's no official KMP implementation, but could probably be replaced with a custom implementation like this?

kirillzh avatar Jul 25 '23 21:07 kirillzh

The blocker at the moment is that for native and JS tests, there is no constructor provided to Kotest. We capture a reference to an instance and invoke the tests on it.

In JVM land we have the class type and can use reflection to create new instances of it.

Until compiler plugins go stable (Kotlin 2.1? 2.2?) it will be too much of a lift to get this working in a way that's stable across versions (Jetbrains make breaking changes even on minor releases).

sksamuel avatar Aug 28 '23 01:08 sksamuel

@sksamuel is there any chance that this will be resolved in Kotest 6.0 with Kotlin 2.0+ support?

kirillzh avatar Aug 15 '24 01:08 kirillzh

I'm aiming to try and support it yes.

sksamuel avatar Aug 15 '24 01:08 sksamuel