skip to content

After declaring a custom `integrationTest` suite, how do you make it actually run as part of the build, and why isn't it included automatically?

level: middleimportance: must knowfreq 70%

answer

  1. only `test` auto-wired into check
  2. tasks.named("check") { dependsOn(...) }
  3. depend on the suite provider, not the name string
  4. shouldRunAfter(test) for ordering
  5. build → check → your suite

basics

~10 s

Custom suites aren't wired into check by default. Add tasks.named("check") { dependsOn(testing.suites.named("integrationTest")) } so running check (and thus build) also runs integration tests.

solid answer

~40 s

Only the built-in `test` suite is wired into the `check` lifecycle task. A custom suite like `integrationTest` is registered and runnable (`gradle integrationTest`) but **will not run** during `check`/`build` until you explicitly make `check` depend on it. The idiomatic wiring is: ```kotlin tasks.named("check") { dependsOn(testing.suites.named("integrationTest")) } ``` This is deliberate: integration tests are often slow or require external resources, so Gradle leaves the decision to you. Once wired, `check` runs `test` then `integrationTest` (order isn't guaranteed unless you add `shouldRunAfter(test)`), and because `build` depends on `check`, CI that runs `build` will exercise the suite too. Prefer depending on the suite provider rather than hardcoding the task name so it stays lazy and rename-safe.

code

kotlin · 13 lines
kotlin
testing {
    suites {
        val integrationTest by registering(JvmTestSuite::class) {
            targets {
                all { testTask.configure { shouldRunAfter(test) } }
            }
        }
    }
}

tasks.named("check") {
    dependsOn(testing.suites.named("integrationTest"))
}

go deeper

for a junior

Know that check doesn't run custom suites until you add dependsOn.

for a middle

Write the tasks.named("check") { dependsOn(...) } wiring and explain the build→check chain.

for a senior

Distinguish dependsOn from shouldRunAfter, use lazy providers, and justify fail-fast ordering.

for a principal

Define the org-wide convention (e.g. a convention plugin) so every module wires integration suites consistently into CI.

## The lifecycle gap Gradle's `check` task is the aggregate verification entry point; `build` depends on `check`. The `java` plugin wires the built-in **`test`** suite into `check` automatically. **Custom suites are not.** So after you declare an `integrationTest` suite you can run it directly (`gradle integrationTest`), but `gradle check` / `gradle build` will silently skip it. This is intentional — integration/functional suites are frequently slow, flaky, or need databases/containers, so Gradle refuses to assume they belong on the default verification path. ## Wiring it in The canonical fix is to add a dependency from `check` to the suite: ```kotlin tasks.named("check") { dependsOn(testing.suites.named("integrationTest")) } ``` Using `testing.suites.named("integrationTest")` returns a lazy provider; `dependsOn` accepts it and Gradle resolves it to the suite's run task. You could also write `dependsOn("integrationTest")`, but the provider form is lazier and survives refactors. ## Ordering vs. dependency `dependsOn` only guarantees the integration suite *runs*, not *when* relative to unit tests. To make integration tests run after unit tests (fail fast on the cheap ones first), add ordering inside the suite's target: ```kotlin testing { suites { val integrationTest by registering(JvmTestSuite::class) { targets { all { testTask.configure { shouldRunAfter(test) } } } } } } tasks.named("check") { dependsOn(integrationTest) } ``` `shouldRunAfter` is a *soft* ordering hint (not a hard dependency), so it won't force unit tests to run when you ask only for `integrationTest`, but it orders them when both are scheduled. ## Why not just call it from `test`? Making `test` depend on `integrationTest` would conflate scopes and force integration tests whenever anyone runs unit tests — the opposite of fail-fast. Wiring at the `check` aggregate keeps unit and integration runnable independently while still guaranteeing CI (`build` → `check`) covers both.

  • Does wiring `check` to depend on the suite also affect `build`?
    Yes — `build` depends on `check`, so once `check` pulls in the suite, `gradle build` runs it too.
  • What's the difference between `dependsOn(integrationTest)` and `shouldRunAfter(test)`?
    `dependsOn` guarantees execution; `shouldRunAfter` only orders the two when both are already scheduled, without forcing either.
  • Why doesn't Gradle wire custom suites into `check` automatically?
    Integration suites are often slow or need external infra, so Gradle leaves the policy decision to the build author.

saying these in an interview costs you the question

  • Assuming declaring the suite is enough to run it in CI.
  • Making `test` depend on `integrationTest` (forces slow tests on every unit run).
  • Using `mustRunAfter`/`shouldRunAfter` and expecting it to also force the dependency.

context