How do you control which tests Surefire runs using includes/excludes patterns and the -Dtest command-line filter?
answer
- includes replace defaults
- -Dtest=Class#method
- wildcards & negation !
- failIfNoSpecifiedTests
- JUnit5 groups/excludedGroups
basics
~10 sConfigure <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 sSurefire'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 linesmvn test -Dtest='UserServiceTest#shouldSave*,Order*Test'
mvn test '-Dtest=!FlakyTest' -DfailIfNoTests=falsego deeper
Know you can run one class with -Dtest=ClassName.
Know includes/excludes replace defaults and -Dtest supports class#method and wildcards.
Use tag/group filtering and the failIfNoTests flags deliberately in CI profiles.
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.