skip to content

How do you control which tests Surefire runs using includes/excludes patterns and the -Dtest command-line filter?

level: middleimportance: must knowfreq 70%

answer

  1. includes replace defaults
  2. -Dtest=Class#method
  3. wildcards & negation !
  4. failIfNoSpecifiedTests
  5. JUnit5 groups/excludedGroups

basics

~10 s

Configure <includes>/<excludes> patterns in the plugin to match test class names. From the command line, run a subset with -Dtest=ClassName, -Dtest=ClassName#method, or wildcards like -Dtest='*IT' to override the defaults for that run.

solid answer

~30 s

Surefire's default includes are name-based: classes ending in Test/Tests/TestCase or starting with Test. You override this in the POM with <configuration><includes>/<excludes>, each holding <include>/<exclude> patterns (e.g. **/*Spec.java) so non-standard names get picked up or noisy ones get filtered out. For ad-hoc runs, -Dtest takes precedence: -Dtest=UserServiceTest runs one class, -Dtest=UserServiceTest#shouldSave runs one method, -Dtest='*ServiceTest,Order*' runs multiple/wildcards, and -Dtest='!SlowTest' excludes. JUnit 5 also supports tag filtering via groups/excludedGroups. A key gotcha: by default an empty/no-match -Dtest fails the build (failIfNoTests / failIfNoSpecifiedTests), and includes/excludes apply to compiled class names under target/test-classes, not source files.

code

bash · 2 lines
bash
mvn test -Dtest='UserServiceTest#shouldSave*,Order*Test'
mvn test '-Dtest=!FlakyTest' -DfailIfNoTests=false

go deeper

for a junior

Know you can run one class with -Dtest=ClassName.

for a middle

Know includes/excludes replace defaults and -Dtest supports class#method and wildcards.

for a senior

Use tag/group filtering and the failIfNoTests flags deliberately in CI profiles.

for a principal

Standardize naming + tagging conventions so unit/integration/slow tests are selected consistently across modules and CI stages.

## Default selection Surefire automatically runs test classes whose names match `**/Test*.java`, `**/*Test.java`, `**/*Tests.java`, `**/*TestCase.java`. The patterns are evaluated against the **compiled** classes in `target/test-classes`, but written with `.java`/`.class` interchangeably. ## Configuring includes/excludes in the POM When your team uses a different convention (e.g. `*Spec`), declare it explicitly: ```xml <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>3.2.5</version> <configuration> <includes> <include>**/*Test.java</include> <include>**/*Spec.java</include> </includes> <excludes> <exclude>**/*IntegrationTest.java</exclude> <exclude>**/Abstract*.java</exclude> </excludes> </configuration> </plugin> ``` Note: declaring `<includes>` **replaces** the defaults, so list every pattern you want. ## Command-line filtering with -Dtest `-Dtest` overrides includes/excludes for that invocation: ```bash mvn test -Dtest=UserServiceTest # one class mvn test -Dtest=UserServiceTest#shouldSaveUser # one method mvn test -Dtest='UserServiceTest#save*|find*' # method patterns mvn test -Dtest='*ServiceTest,Order*Test' # multiple / wildcard mvn test '-Dtest=!SlowTest' # exclusion (negation) ``` ## JUnit 5 tags With the JUnit Platform you can filter by `@Tag` instead of class names: ```xml <configuration> <groups>fast</groups> <excludedGroups>slow</excludedGroups> </configuration> ``` ## Common gotchas - **`failIfNoTests` / `failIfNoSpecifiedTests`** default to true, so a typo'd `-Dtest=` that matches nothing fails the build. Set `-DfailIfNoTests=false` to allow empty runs. - Patterns operate on class names, so `**/*Test.java` matches `FooTest`, not a `Foo` class containing tests. - Overriding `<includes>` removes the built-in defaults entirely.

  • If you add a single <include>, what happens to the default patterns?
    They are replaced. The defaults no longer apply, so you must list every pattern you want Surefire to match.
  • Why might mvn test -Dtest=Typo fail even though nothing ran?
    failIfNoSpecifiedTests defaults to true; a -Dtest that matches no class fails the build unless you set it false.
  • How do you filter JUnit 5 tests by category without renaming classes?
    Use @Tag on the tests and Surefire <groups>/<excludedGroups> (or -Dgroups=...).

saying these in an interview costs you the question

  • Believing <includes> is additive to the defaults.
  • Assuming -Dtest with no matches silently passes.
  • Thinking -Dtest can't target individual methods.

context