In the JVM Test Suites DSL, what is a suite 'target' and how does it relate to the Test task that actually runs?
answer
- target = one execution of a suite
- target.testTask = the real Test task
- configure via targets { all { testTask.configure {} } }
- default: one target named like the suite
- never configure Test by name here
basics
~10 sA target is a runnable execution of a suite. Each target owns a Test task (its testTask). Configuring the target's testTask is how you tweak how that suite actually runs.
solid answer
~40 sInside a `testing.suites` suite, a **target** represents one concrete execution of that suite against a particular environment; by default every suite gets one target whose name matches the suite. The target wraps the real `org.gradle.api.tasks.testing.Test` task that runs the tests, exposed as `target.testTask`. You don't configure the Test task directly — you go through `targets { all { testTask.configure { ... } } }` so settings apply to every target the suite produces. This is where you set things like `maxParallelForks`, `useJUnitPlatform()` overrides, system properties, or `shouldRunAfter(test)`. Separating the suite (the logical grouping with its sources and dependencies) from its targets (the executions) is what lets a single suite later fan out into multiple environments while sharing one configuration block.
code
kotlin · 14 linestesting {
suites {
val integrationTest by registering(JvmTestSuite::class) {
targets {
all {
testTask.configure {
maxParallelForks = 2
shouldRunAfter(test)
}
}
}
}
}
}go deeper
Know that a suite runs via a Test task and you tweak it under targets.
Explain suite vs. target vs. testTask and configure through targets { all { testTask.configure {} } }.
Discuss laziness of testTask (TaskProvider) and why the indirection survives renames and supports multiple targets.
Frame targets as the extension point for fanning one suite across environments/JDKs while centralizing configuration policy.
## Suites vs. targets vs. Test tasks The JVM Test Suites plugin (built into the `java` plugin, stabilized in Gradle 7.6+) introduces three nested concepts: - **Suite** — a logical group of tests with its own source set, dependencies, and a JVM/toolchain. `test` is the built-in suite; you add others like `integrationTest`. - **Target** — a *concrete execution* of a suite. By default a suite has exactly one target with the same name as the suite. A target is the thing that owns a real task. - **Test task** — the actual `org.gradle.api.tasks.testing.Test` task that forks JVMs and runs your tests. Each target exposes it as `target.testTask`, a lazy `TaskProvider<Test>`. The key idea: **you never configure the `Test` task by name** in this DSL. You reach it through the target so your configuration is bound to the suite's lifecycle and survives renames. ## Configuring through `targets` ```kotlin testing { suites { val integrationTest by registering(JvmTestSuite::class) { targets { all { testTask.configure { maxParallelForks = 2 systemProperty("env", "ci") } } } } } } ``` `targets { all { ... } }` iterates every target of the suite. `testTask.configure { ... }` is lazy (it's a `TaskProvider`), so the Test task is only realized when needed. Anything you can set on a `Test` task — `useJUnitPlatform()`, `filter`, `jvmArgs`, `systemProperty`, `maxHeapSize`, `shouldRunAfter(...)` — goes inside that `configure` block. ## Why the indirection matters Because the target abstracts "one run," a suite can in principle expose several targets (e.g., one per JDK or per environment) while you write the configuration once under `all { ... }`. The suite holds *what* to test; targets hold *how/where* it runs. The built-in `test` suite is just a suite with a single target named `test` backed by the familiar `test` task.
- How many targets does a suite have by default and what is it named?Exactly one, named the same as the suite (e.g. an `integrationTest` suite has an `integrationTest` target).
- Why use `testTask.configure { }` instead of grabbing the Test task eagerly?`testTask` is a lazy `TaskProvider`; `configure` defers realization, keeping configuration-avoidance benefits and avoiding ordering pitfalls.
A suite is a recipe; a target is one actual cooking session in a specific kitchen; the testTask is the stove you tune for that session.
saying these in an interview costs you the question
- Saying a target IS the Test task — it owns/wraps one via `testTask`.
- Claiming you should look up and mutate the `Test` task by name instead of going through the target.