skip to content

After activating useJUnitPlatform(), how do you make Gradle run only tests carrying a specific JUnit 5 @Tag, configured from the build script?

level: middleimportance: should knowfreq 45%

answer

  1. useJUnitPlatform { includeTags / excludeTags }
  2. matches @Tag annotations
  3. includeEngines / excludeEngines by id
  4. tag expressions: fast & !flaky
  5. different from --tests name filter

basics

~10 s

Pass a configuration closure to useJUnitPlatform and use includeTags/excludeTags, e.g. useJUnitPlatform { includeTags("fast"); excludeTags("slow") }. This filters by JUnit 5 @Tag at the Platform level.

solid answer

~30 s

`useJUnitPlatform()` accepts an optional configuration action exposing **Platform-specific** options — most notably tag filtering: ```kotlin tasks.named<Test>("test") { useJUnitPlatform { includeTags("fast") excludeTags("slow", "integration") includeEngines("junit-jupiter") } } ``` `includeTags`/`excludeTags` match JUnit 5 `@Tag("...")` annotations; `includeEngines`/`excludeEngines` filter by Platform engine id (e.g. `junit-jupiter`, `junit-vintage`). This is distinct from Gradle's generic `filter`/`--tests` class-name include patterns, which work regardless of framework. A common pattern is a separate `integrationTest` task or suite that `includeTags("integration")` while the main `test` task excludes it, so the fast feedback loop stays fast. Tag expressions also support boolean syntax like `"fast & !flaky"`.

code

kotlin · 7 lines
kotlin
tasks.named<Test>("test") {
    useJUnitPlatform {
        includeTags("fast & !flaky")
        excludeTags("slow")
        includeEngines("junit-jupiter")
    }
}

go deeper

for a junior

Recall that useJUnitPlatform can take a block and that includeTags/excludeTags exist for @Tag filtering.

for a middle

Write the closure correctly and distinguish tag filtering from name-based --tests/filter selection.

for a senior

Design a fast/slow split using tags plus a dedicated task or suite, and know tag expression syntax and engine filtering.

for a principal

Define org conventions for tag taxonomy (fast/slow/integration) and bake the filtering into shared convention plugins and CI stages.

## Why the configuration closure exists `useJUnitPlatform()` can be called bare, but it also takes a configuration action of type `JUnitPlatformOptions`. Because the JUnit Platform has features the generic `Test` task doesn't know about (tags, engine selection), Gradle exposes them through this options object rather than on the task directly. ## Tag filtering JUnit 5 lets you annotate tests with `@Tag("slow")`, `@Tag("integration")`, etc. The Platform options expose: - `includeTags(vararg)` — run only tests matching these tag expressions. - `excludeTags(vararg)` — skip tests matching these. Arguments are **tag expressions**, so you can write `"fast & !flaky"`, `"api | web"`, or `"!slow"`. ## Engine filtering - `includeEngines("junit-jupiter")` / `excludeEngines("junit-vintage")` filter by **engine id**. Useful when both Jupiter and Vintage are present and you want to run only one. ## How this differs from Gradle's generic filtering Gradle's `Test` task also has framework-agnostic filtering: - `filter { includeTestsMatching("*IntegrationTest") }` and the `--tests` CLI flag match by **fully-qualified class/method name patterns**. These two layers stack: name filters narrow which classes run; tag filters narrow which methods within them run. ## A practical split ```kotlin tasks.named<Test>("test") { useJUnitPlatform { excludeTags("slow") } } tasks.register<Test>("slowTest") { useJUnitPlatform { includeTags("slow") } // reuse the test source set's classpath testClassesDirs = sourceSets["test"].output.classesDirs classpath = sourceSets["test"].runtimeClasspath } ``` This keeps the default `test` task fast and routes the slow suite to a dedicated task or, more idiomatically, a separate `JvmTestSuite`. ## Gotcha Tag filtering only works because the Platform is active. If you're on `useJUnit()` (JUnit 4), `includeTags`/`excludeTags` aren't available — JUnit 4 has its own `@Category` mechanism instead.

  • What's the difference between excludeTags("slow") and filter { excludeTestsMatching("*SlowTest") }?
    excludeTags matches the JUnit 5 @Tag annotation at the Platform level; the filter/--tests mechanism matches by class/method name pattern and is framework-agnostic. They operate on different criteria and can be combined.
  • Can you use includeTags with useJUnit()?
    No — tag include/exclude is a JUnit Platform feature available only via useJUnitPlatform. JUnit 4 uses @Category and the categories runner instead.

saying these in an interview costs you the question

  • Claiming includeTags filters by class name — it filters by the @Tag annotation value.
  • Saying tag filtering works under useJUnit() — it's a Platform-only feature.

context