How does `useJUnitJupiter()` inside the default `test` suite replace manual `testImplementation`/`testRuntimeOnly` dependency wiring?
answer
- adds junit-jupiter + platform-launcher
- configures useJUnitPlatform automatically
- single source of truth for framework
- version arg or Provider overload
- swap to useJUnit/useTestNG one-liner
basics
~20 suseJUnitJupiter() tells the suite to use JUnit 5. Gradle then adds the JUnit Jupiter API/engine and platform launcher dependencies to the suite's classpath and configures the test task's useJUnitPlatform(), so you don't add them by hand.
solid answer
~40 sCalling `useJUnitJupiter()` on a `JvmTestSuite` does two coordinated things. First, it injects the correct JUnit 5 dependencies onto the suite's implementation/runtime classpath — `junit-jupiter` (API + params + engine) plus the platform launcher — without you writing any `testImplementation("org.junit.jupiter:…")` lines. Second, it configures the suite's `Test` task to run on the JUnit Platform (equivalent to `useJUnitPlatform()`). So a single declarative call replaces both the dependency declarations *and* the test-task framework configuration that you previously did separately. You can pin the version with `useJUnitJupiter("5.10.2")` or a `Provider`. Switching frameworks is a one-liner: change to `useJUnit()` (JUnit 4) or `useTestNG()` and the dependencies and task config follow automatically — there's a single source of truth for the suite's framework.
code
kotlin · 8 linestesting {
suites {
val test by getting(JvmTestSuite::class) {
// adds JUnit 5 deps AND sets useJUnitPlatform() on the test task
useJUnitJupiter(libs.versions.junit) // Provider overload from a version catalog
}
}
}go deeper
Know that useJUnitJupiter() selects JUnit 5 and you no longer hand-add the JUnit dependency or useJUnitPlatform().
Explain both effects — dependency injection plus test-task platform configuration — and that it's a single source of truth.
Discuss the Provider/version-catalog overload, the boundary (framework vs your own test libs), and how this reduces config drift.
Position it as a convention you enforce org-wide so every module's test plumbing is identical and centrally versioned.
## The old way (manual wiring) To run JUnit 5 the classic way you'd write: ```kotlin dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.2") testRuntimeOnly("org.junit.platform:junit-platform-launcher") } tasks.test { useJUnitPlatform() } ``` Three responsibilities, three places to get wrong: the API/engine dependency, the runtime launcher, and the test task's framework switch. ## The suite way Inside the suite you instead write: ```kotlin testing { suites { val test by getting(JvmTestSuite::class) { useJUnitJupiter("5.10.2") } } } ``` `useJUnitJupiter(...)` is a method on `JvmTestSuite` that: 1. **Adds the framework dependencies** to the suite's own `implementation`/`runtimeOnly` dependency buckets — the `junit-jupiter` aggregate and the `junit-platform-launcher`. These land on the suite's compile/runtime classpath automatically. 2. **Configures the suite's `Test` task** to use the JUnit Platform — you do not also call `useJUnitPlatform()`. ## Why this is better - **Single source of truth:** the framework choice lives in one call; dependencies and task config can't drift apart. - **Version is centralized:** `useJUnitJupiter("5.10.2")` (overload also accepts a `Provider<String>`, handy with a version catalog). - **Framework swaps are trivial:** replace with `useJUnit()`, `useTestNG()`, `useSpock()`, or `useKotlinTest()` and everything follows. - **No-arg default:** `useJUnitJupiter()` uses a Gradle-managed default version, useful for quick starts though pinning is preferred for reproducibility. ## What it does NOT do It does not pull in *your* test libraries (AssertJ, Mockito, Testcontainers). Those you still declare — but you declare them on the suite via its `dependencies {}` block, not the project-level `testImplementation`. The framework call only handles the test *framework* plumbing.
- Do you still call `tasks.test { useJUnitPlatform() }` when using `useJUnitJupiter()`?No. `useJUnitJupiter()` already configures the suite's test task to run on the JUnit Platform; adding `useJUnitPlatform()` manually is redundant.
- Does `useJUnitJupiter()` add your assertion/mocking libraries?No — it only adds the JUnit framework dependencies. AssertJ, Mockito, etc. you still declare yourself, ideally on the suite's own `dependencies {}` block.
- How would you pin the version from a version catalog?Use the `Provider` overload: `useJUnitJupiter(libs.versions.junit)`, keeping the version centralized in `libs.versions.toml`.
saying these in an interview costs you the question
- Saying you must still manually add `junit-platform-launcher` — the framework call handles it.
- Calling both `useJUnitJupiter()` and `useJUnitPlatform()` and thinking both are required.
- Believing `useJUnitJupiter()` brings in AssertJ/Mockito.