maven-surefire-plugin
The Maven Surefire plugin is one of the most important components in the Maven test lifecycle. Although its name sounds simple, it plays a central role in how Java projects run unit tests, integration tests, and other test suites during a build.
When you execute commands such as mvn test or mvn package, Maven does not run tests directly. Instead, it follows the lifecycle phases and binds the Surefire plugin to the test phase. From there, Surefire takes over the responsibility of finding, selecting, and executing test classes.
How It Works During the Test Phase
Surefire operates after test compilation. It looks for compiled test classes in the expected output directory and then applies naming conventions to decide which classes should run.
The default include patterns include:
**/Test*.java**/*Test.java**/*Tests.java**/*TestCase.java
After selecting candidate classes, Surefire uses the test framework provider already present in the project dependencies. Common providers include JUnit 4, JUnit 5, and TestNG.
The plugin then launches a separate JVM process, often called a fork, to run the tests. This helps isolate failures and avoid interference between tests. After execution, it writes results to the console and creates reports in the target/surefire-reports directory. Both XML and TXT formats are commonly generated.
Declaring a Modern Version
Older Maven versions may bind an outdated Surefire version by default, which can limit functionality. In many projects, it is better to declare a current 3.x version explicitly in the pom.xml.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
</plugin>
</plugins>
</build>
Configuring the Surefire Plugin
Skipping Tests
There are several ways to skip tests. For example, you can use:
mvn package -DskipTests
mvn package -Dmaven.test.skip=true
The first option skips test execution but still compiles test code. The second option skips both compilation and execution. You can also set this in the plugin configuration:
<configuration>
<skipTests>true</skipTests>
</configuration>
Including and Excluding Tests
Sometimes the default naming rules are not enough. You may want to run only integration tests or exclude slow tests. Surefire supports includes and excludes patterns.
<configuration>
<includes>
<include>**/*IntegrationTest.java</include>
</includes>
<excludes>
<exclude>**/SlowTest.java</exclude>
</excludes>
</configuration>
Setting JVM Arguments
You can pass JVM arguments through the argLine property. This is useful for heap size, encoding, or debugging tools.
<configuration>
<argLine>-Xmx1024m -Dfile.encoding=UTF-8</argLine>
</configuration>
A common practice is to use the @{argLine} placeholder so that Surefire can work together with coverage tools such as JaCoCo without overwriting each other's arguments.
<properties>
<argLine>-Xmx1024m</argLine>
</properties>
<configuration>
<argLine>@{argLine} -Dfile.encoding=UTF-8</argLine>
</configuration>
Improving Test Execution Speed
As test suites grow, running tests serially can slow down the build. Surefire provides parallel execution features.
You can configure parallel execution by method, class, or both:
<configuration>
<parallel>methods</parallel>
<threadCount>4</threadCount>
</configuration>
Valid values for parallel include methods, classes, and classesAndMethods. The threadCount controls how many threads run. You can also control the number of forked JVM processes with forkCount.
<configuration>
<forkCount>2</forkCount>
<reuseForks>true</reuseForks>
</configuration>
A forkCount of 2 starts two JVM processes for tests. When reuseForks is true, multiple test classes can reuse the same process, reducing startup overhead.
Parallel execution can significantly improve speed, but tests must be thread-safe. Shared mutable state can cause flaky failures.
Working With JUnit 5
JUnit 5 uses the JUnit Platform. Surefire gained native support for it starting with version 2.22.0. With Surefire 3.x, if your project includes the junit-jupiter dependency, the plugin can automatically detect and load the JUnit Platform provider.
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
If you need to pass filtering conditions to the platform, you can use configurationParameters or include the relevant JUnit Platform artifacts. If tests are not being recognized, check whether the Surefire version is too old.
Troubleshooting Common Issues
- Tests not running: Check class names against default patterns, or use
includesexplicitly. Confirm