skip to content

What does the `filter {}` block inside a `Test` task do, and how do `includeTestsMatching` and `excludeTestsMatching` work?

level: juniorimportance: must knowfreq 55%

answer

  1. filter {} on Test task
  2. includeTestsMatching / excludeTestsMatching
  3. FQN + * wildcard
  4. OR-ed inclusions
  5. failOnNoMatchingTests default true

basics

~10 s

The filter {} block on a Test task selects which tests run by pattern. includeTestsMatching('*Foo*') keeps only matching tests; excludeTestsMatching drops matching ones. Patterns match fully-qualified class/method names with * wildcards.

solid answer

~30 s

Every `Test` task (like `test`) exposes a persistent `filter {}` block in the build script. `includeTestsMatching(pattern)` whitelists tests whose fully-qualified name matches; `excludeTestsMatching(pattern)` blacklists them. Patterns use `*` as a wildcard and dot-separate package, class and method (`com.acme.OrderTest.shouldPay`, `*IntegrationTest`, `*.slow*`). Multiple include patterns are OR-ed together. Unlike the transient `--tests` command-line option, `filter {}` is declared in the build and applies on every run, making it the right tool for permanent partitioning (e.g. excluding slow tests from the default `test` task). By default `failOnNoMatchingTests` is true, so a pattern matching nothing fails the build — useful to catch typos.

code

kotlin · 7 lines
kotlin
tasks.test {
    filter {
        includeTestsMatching("com.acme.*Test")
        excludeTestsMatching("*SlowTest")
        isFailOnNoMatchingTests = true
    }
}

go deeper

for a junior

Know that filter {} selects tests by name pattern with *, and the include/exclude method names.

for a middle

Explain FQN matching, OR-ing of includes, exclude-wins precedence, and failOnNoMatchingTests.

for a senior

Contrast persistent build-script filtering with transient --tests; know when to prefer tags over name patterns.

for a principal

Frame name-filters as brittle coupling to naming conventions; advocate tag-based categorization as the governance-friendly partitioning strategy across many modules.

## What the filter block is Gradle's JVM test execution is driven by `Test` tasks (the built-in `test` task is one; you can register more). Each `Test` task carries a `TestFilter` accessed through the `filter {}` configuration block. The filter narrows the set of discovered tests **before** they execute, independent of the test engine (JUnit 4, JUnit Platform, TestNG). ## The two methods - `includeTestsMatching(String pattern)` — adds an **inclusion** pattern. If any inclusion pattern is present, only tests matching at least one of them run (inclusions are OR-ed). - `excludeTestsMatching(String pattern)` — adds an **exclusion** pattern. Any test matching it is dropped, even if it matched an inclusion. ## Pattern syntax Patterns are matched against the **fully-qualified name** in the form `package.Class.method`. The only wildcard is `*` (matches any sequence of characters, including dots). Examples: - `com.acme.OrderTest` — every method of that class - `com.acme.OrderTest.shouldChargeCard` — a single method - `*IntegrationTest` — every class whose simple/qualified name ends in `IntegrationTest` - `*.ui.*` — anything in a `ui` sub-package There is no `?` single-char wildcard and no regex; it is glob-like only. ## Persistent vs. transient `filter {}` is **declared in the build script**, so it applies on every invocation of that task — the natural place to permanently shape a task (e.g. an `integrationTest` task that only ever runs `*IT`). The command-line `--tests` option is a **one-off override** for a single run and lives in the sibling topic. ## failOnNoMatchingTests ```kotlin tasks.test { filter { includeTestsMatching("*FastTest") isFailOnNoMatchingTests = true // default } } ``` With the default `true`, a filter that selects zero tests fails the build, catching renamed-away or mistyped patterns. Set it to `false` when an empty result is legitimate (e.g. a task that may have nothing to run in some modules). ## How it relates to tags The `filter {}` block matches on **names**. To partition by semantic category (slow/fast/db) you typically use JUnit Platform `@Tag` plus `useJUnitPlatform { includeTags(...) }` — a complementary mechanism. Name-filtering and tag-filtering can be combined on the same task.

  • If both an include and an exclude pattern match the same test, what happens?
    Exclusion wins — the test is dropped. Excludes are applied after includes.
  • What wildcard characters does the pattern support?
    Only `*`. It is glob-like, not a regex; there is no `?` and no character classes.

saying these in an interview costs you the question

  • Claiming the patterns are regular expressions (they are glob-like with only `*`).
  • Saying `filter {}` only works with JUnit 5 — it is engine-agnostic and pre-dates the platform.
  • Confusing `filter {}` with the `--tests` CLI flag as if they were the same persistent mechanism.

context