What Gradle/source-set setup is required to write kotlin.test tests in common code for a multiplatform module, and how do you pick the JVM test runner?
answer
- implementation(kotlin("test")) in commonTest
- plugin auto-wires per-target runners
- useJUnitPlatform() for JUnit 5 on jvmTest
- src/commonTest vs src/jvmTest split
- ./gradlew allTests aggregates targets
basics
~20 sAdd the kotlin-test dependency to the commonTest source set and put your tests there using kotlin.test imports. For the JVM you pick JUnit 4 or 5 either by a small dependency or by calling useJUnitPlatform() on the test task.
solid answer
~40 sIn a Kotlin Multiplatform build, you declare a dependency on `kotlin("test")` in the `commonTest` source set; the Kotlin Gradle plugin automatically wires the matching platform test runners (JUnit on JVM, the JS runner, Kotlin/Native runner). Your shared tests live in `src/commonTest/kotlin` using `kotlin.test` annotations and assertions. For the JVM runner choice: with newer Kotlin versions JUnit 4 is the default for the JVM target, but you opt into JUnit Platform/Jupiter by configuring the JVM test task with `useJUnitPlatform()` (and/or depending on `kotlin-test-junit5`). Platform-specific tests go in their own source sets like `src/jvmTest`, `src/jsTest`, `src/nativeTest`, where you may use framework-specific features not available in common.
go deeper
Knows tests go in commonTest and need the kotlin test dependency.
Configures kotlin("test") in commonTest and selects the JVM runner with useJUnitPlatform().
Explains source-set boundaries, when to drop to jvmTest, and the runner-selecting artifacts.
Reasons about CI aggregation (allTests), report wiring, and keeping the common surface portable across targets.
## Source set layout A KMP module has source sets named `<target>Main` and `<target>Test`, plus the shared `commonMain`/`commonTest`: ``` src/ commonMain/kotlin/ <- shared production code commonTest/kotlin/ <- shared tests (kotlin.test) jvmMain/kotlin/ jvmTest/kotlin/ jsMain/kotlin/ jsTest/kotlin/ nativeMain/kotlin/ nativeTest/kotlin/ ``` ## The one dependency you need ```kotlin kotlin { jvm() js(IR) { nodejs() } // native targets... sourceSets { commonTest.dependencies { implementation(kotlin("test")) // pulls kotlin-test for every target } } } ``` `kotlin("test")` resolves to the multiplatform `kotlin-test` artifact. The Kotlin Gradle plugin **auto-aligns** the per-target backings: JUnit for JVM, the JS test runner, and the Kotlin/Native runner. You do **not** add JUnit by hand for the basic case. ## Choosing the JVM runner The JVM target can run on JUnit 4 or the JUnit Platform (Jupiter / JUnit 5): ```kotlin // JUnit Platform / Jupiter on the JVM target: kotlin { jvm() } tasks.named<Test>("jvmTest") { useJUnitPlatform() } // and/or depend on kotlin-test-junit5 in jvmTest ``` - **`useJUnitPlatform()`** switches the Gradle `Test` task to the JUnit Platform launcher (needed for JUnit 5). - The `kotlin-test-junit` vs `kotlin-test-junit5` artifact selects which framework kotlin.test's JVM annotations alias to. With recent Kotlin, the plugin defaults the JVM target to JUnit 4 unless you opt into the platform. ## Where platform-specific tests live If a test needs JVM-only APIs (files, threads) or JUnit 5 features (`@ParameterizedTest`, `@Nested`), put it in `src/jvmTest` and import the framework directly. Tests in `commonTest` must stay platform-neutral. ## Running - `./gradlew allTests` — runs every target's tests and aggregates a report. - `./gradlew jvmTest`, `jsTest`, `nativeTest` — run a single target. ## Common mistake Adding `org.junit.jupiter:junit-jupiter` to `commonTest` — it won't compile for JS/Native. JUnit dependencies belong only in `jvmTest` (or are pulled transitively by `kotlin("test")` for the JVM target).
- Where does a test that needs java.io.File go?In src/jvmTest, not commonTest — file APIs are JVM-only, so the test can't compile for JS/Native.
- What does ./gradlew allTests do?It runs the test tasks for all configured targets and produces an aggregated multiplatform test report.
saying these in an interview costs you the question
- Adding junit-jupiter directly to commonTest
- Manually adding kotlin-test per target instead of once in commonTest
- Forgetting useJUnitPlatform() then wondering why JUnit 5 tests don't run
- Putting JVM-only tests in commonTest and breaking the JS/Native build