0

I'm working with Kotlin Multiplatform in a multi-module setup. I want to create a dedicated module that defines reusable test setup and teardown logic—similar to JUnit rules—in the commonMain source set. This module should be consumed by other modules via their respective commonTest source sets to avoid duplication.

The goal is for each module to seamlessly reuse the shared setup logic by adding this common module as a test dependency.

What I'm Trying to Achieve

  • Define shared test hooks using @BeforeTest and @AfterTest in the commonMain source set.
  • Reuse this setup logic across multiple modules.
  • Allow each module to easily consume the shared logic in their commonTest source sets.

The Issue

Although the IDE correctly resolves the kotlin.test annotations in the commonMain source set, the test runner fails to recognize them during execution. Specifically, the @BeforeTest and @AfterTest annotations from the kotlin.test package are not recognized when running tests.

My Question

What is the recommended way to define and share reusable @BeforeTest and @AfterTest hooks from commonMain so that they can be reliably used in commonTest across multiple modules?

How can I structure this setup to ensure proper test execution, reusability, and maintainability?

Any examples, insights, or best practices would be greatly appreciated!

2
  • 1
    What do you mean exactly by "sharing". You can just implement a method, and then call that from @BeforeTest somehwere else? But I assume you want the @BeforeHook to be automatically executed and not have the annotation present in the test anymore? Commented Jun 5 at 10:45
  • Exactly, I want to create a "base" test class with some code that should run before and after each test case. I want to have this base class in one module that can be consumed by any other of my modules in their commonTest set. Commented Jun 11 at 20:55

1 Answer 1

0

Ok, I can't tell you exactly what is wrong in your current setup, but I can suggest a structure that I would use:

build.gradle.kts

plugins {
    kotlin("multiplatform") version "1.9.0"
}

repositories {
    mavenCentral()
}

kotlin {
    jvm()
    js(IR) {
        browser()
    }

    sourceSets {
        val commonMain by getting {
            dependencies {
                implementation(kotlin("stdlib-common"))
            }
        }
        val commonTest by getting {
            // Do not declare "test" dependencies in "main" source sets.
            // Define your test base class in this source set.
            dependencies {
                implementation(kotlin("test"))
            }
        }
    }
}

As mentioned in the comment above, you should avoid your "main" source sets to depend on "test" libraries. One simple reason is that these libraries will also be packaged and shipped with your software, and you normally would not want that.

src/commonTest/kotlin/BaseTest.kt

import kotlin.test.*

open class BaseTest {

    @BeforeTest
    fun before() {
        println("Shared setup logic")
    }

    @AfterTest
    fun after() {
        println("Shared teardown logic")
    }
}

src/jvmTest/kotlin/MyJvmTest.kt

import kotlin.test.*

class MyJvmTest : BaseTest() {

    @Test
    fun test() {
        println("JVM test running!")
        assertEquals(2, 1 + 1)
    }
}

This should do what you want, and give you a good idea about how to structure your project.

Sign up to request clarification or add additional context in comments.

4 Comments

I have several Gradle modules. Every one of these modules is a Kotlin Multiplatform module in itself. I want to have one single module, let's call it :test-sdk that provides the test base classes that can then be consumed by all other KMP modules in their commonTest source sets.
Then you would need to change the structure in Gradle so that these modules depend on each other, instead of source sets. E.g. dependencies { testImplementation(project(':test-sdk')) }.
That was also my first idea but unfortunately testImplementation(..) seems not to be available for Kotlin Multiplatform sourceSets {..} dependencies.. you can just do the regular implementation(..)`
Its not sourceSet.dependencies but project.dependencies, i.e. on the top level of your build script. See docs.gradle.org/current/kotlin-dsl/gradle/org.gradle.api/… and docs.gradle.org/current/kotlin-dsl/gradle/… .

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.