

Splitting Unit and Integration Tests using Maven and Surefire plugin
source link: https://tech.asimio.net/2019/04/08/Splitting-Unit-and-Integration-Tests-using-Maven-and-Surefire-plugin.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Splitting Unit and Integration Tests using Maven and Surefire plugin
Orlando L Otero | Apr 8, 2019
| integration testing, java, maven, maven-surefire-plugin, spring boot, testing, unit testing
| 6 min read
This post has been syndicated by DZone. Also featured on https://www.baeldung.com/java-weekly-276.
1. INTRODUCTION
Generally, when you write Java unit tests, you stub data or mock the target class dependencies. This allows you to verify the business logic in an environment where you don’t depend on third party services.
Integration tests also play an important role in the Continuous Integration / Delivery (CI/CD) process to release software frequent and safe. As I have mentioned before, integration testing goal is to verify that interaction between different parts of the system work well. Examples of such interactions are:
- Connecting to a RDBMS to retrieve or persist data
- Consuming a message from a broker
- Sending an email
- Processing an upstream response
In large Enterprise applications development, with hundreds of unit and integration tests, the test suites take a considerable amount of time to complete, normally hours.

Wouldn’t it make sense to split the tests by their purpose and execution speed? It would be beneficial for an organization to get a quicker feedback when tests fail.
It would then be advisable to implement a fail-fast approach and break the build process when unit tests fail. This post covers configuring Maven’s maven-surefire-plugin to split running unit and integration tests.
2. REQUIREMENTS
- Java 7+.
- Maven 3.2+.
3. THE REST CONTROLLER, UNIT AND INTEGRATION TESTS
Assuming you have generated a Spring Boot 2 application using Spring Initializr, from command line or via your preferred IDE, let’s add a simple REST controller DemoController.java
:
@RestController
@RequestMapping(value = "/api/entities")
public class DemoController {
...
@GetMapping(value = "/{id}")
public ResponseEntity<String> findEntity(@PathVariable String id) {
String entity = this.someBusinessService.findEntity(id);
return new ResponseEntity<>(entity, HttpStatus.OK);
}
}
Let’s now add the unit and integration test classes meant to run during Maven’s test
and integration-test
phases.
DemoControllerTest.java
:
package com.asimio.demo.rest;
...
@RunWith(MockitoJUnitRunner.class)
public class DemoControllerTest {
@Mock
private SomeBusinessService mockSomeBusinessService;
...
@Test
public void shouldRetrieveAnEntity() {
// Given
Mockito.when(this.mockSomeBusinessService.findEntity("blah")).thenReturn("meh");
// When
ResponseEntity<String> actualResponse = this.demoController.findEntity("blah");
// Then
Assert.assertThat(actualResponse.getStatusCode(), Matchers.equalTo(HttpStatus.OK));
Assert.assertThat(actualResponse.getBody(), Matchers.equalTo("meh"));
}
}
DemoControllerIT.java
:
package com.asimio.demo.rest;
...
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = { Application.class })
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class DemoControllerIT {
...
@Test
public void shouldRetrieveAnEventById() {
String body = RestAssured.
given().
accept(ContentType.JSON).
when().
get("/api/entities/blah").
then().
statusCode(HttpStatus.SC_OK).
contentType(ContentType.JSON).
extract().asString();
Assert.assertThat(body, Matchers.equalTo("Retrieved entity with id: blah"));
}
}
4. CONFIGURING maven-surefire-plugin
There are now two unit test classes, DemoControllerTest.java and DefaultSomeBusinessServiceTest
and two integration tests, DemoControllerIT.java and ApplicationTests
. Let’s configure maven-surefire-plugin in pom.xml
to split running them in the test
and integration-test
phases:
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId> <!-- surefire plugin version managed by Spring Boot -->
<configuration>
<skipTests>true</skipTests>
</configuration>
<executions>
<execution>
<id>unit-tests</id>
<phase>test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skipTests>false</skipTests>
<includes>
<include>**/*Test.java</include>
</includes>
</configuration>
</execution>
<execution>
<id>integration-tests</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<skipTests>false</skipTests>
<includes>
<include>**/*IT.*</include>
<include>**/*Tests.*</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
5. RUNNING THE TESTS AND BUILDING THE ARTIFACTS
5.1. A SUCCESSFUL BUILD
Let’s first run and analyze a successful build:
mvn clean verify
...
[INFO] --- maven-surefire-plugin:2.22.1:test (default-test) @ springboot2-split-unit-integration-tests ---
[INFO] Tests are skipped.
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (unit-tests) @ springboot2-split-unit-integration-tests ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.asimio.demo.rest.DemoControllerTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.647 s - in com.asimio.demo.rest.DemoControllerTest
[INFO] Running com.asimio.demo.service.DefaultSomeBusinessServiceTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 s - in com.asimio.demo.service.DefaultSomeBusinessServiceTest
[INFO]
[INFO] Results:
[INFO]
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
...
[INFO] --- maven-jar-plugin:3.1.1:jar (default-jar) @ springboot2-split-unit-integration-tests ---
[INFO] Building jar: /Users/ootero/Projects/bitbucket.org/springboot2-split-unit-integration-tests/target/springboot2-split-unit-integration-tests.jar
[INFO]
[INFO] --- spring-boot-maven-plugin:2.1.4.RELEASE:repackage (repackage) @ springboot2-split-unit-integration-tests ---
[INFO] Replacing main artifact with repackaged archive
[INFO]
[INFO] --- maven-surefire-plugin:2.22.1:test (integration-tests) @ springboot2-split-unit-integration-tests ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.asimio.demo.ApplicationTests
...
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 5.151 s - in com.asimio.demo.ApplicationTests
[INFO] Running com.asimio.demo.rest.DemoControllerIT
...
[INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
...
The verify
phase also executes the test
, package
and integration-test
phases among others. Read more at Maven’s Build Default Lifecycle Reference.
During the test
phase execution, maven-surefire-plugin’s default-test execution was skipped. That’s the result of setting skipTests
to true in pom.xml (lines 5 through 7). The unit-tests execution ran one test in each Test-suffixed class without failure.
Next the package
phase ran and built the main artifact. Then spring-boot-maven-plugin replaced the main jar with an uber jar containing all the dependencies this application needs.
The integration-test
phase ran right after. This time Maven runs test methods found in DemoControllerIT.java and ApplicationTests
classes, ending in a successful build.
Let’s take a look at Maven’s target folder:
ls -1a target/ target/surefire-reports/
target/:
.
..
classes
generated-sources
generated-test-sources
maven-archiver
maven-status
springboot2-split-unit-integration-tests.jar
springboot2-split-unit-integration-tests.jar.original
surefire-reports
test-classes
target/surefire-reports/:
.
..
TEST-com.asimio.demo.ApplicationTests.xml
TEST-com.asimio.demo.rest.DemoControllerIT.xml
TEST-com.asimio.demo.rest.DemoControllerTest.xml
TEST-com.asimio.demo.service.DefaultSomeBusinessServiceTest.xml
com.asimio.demo.ApplicationTests.txt
com.asimio.demo.rest.DemoControllerIT.txt
com.asimio.demo.rest.DemoControllerTest.txt
com.asimio.demo.service.DefaultSomeBusinessServiceTest.txt
Notice the Maven Surefire reports. Stay tuned, I’ll cover uploading these reports and code coverage using JaCoCo to SonarQube in another post; without running the tests twice as I have seen happening when using Cobertura.
5.2. WHEN UNIT TESTS FAIL
Let’s cause a unit test to fail in DemoControllerTest.java as a second scenario:
// Then
Assert.assertThat(actualResponse.getStatusCode(), Matchers.equalTo(HttpStatus.OK));
- Assert.assertThat(actualResponse.getBody(), Matchers.equalTo("meh"));
+ Assert.assertThat(actualResponse.getBody(), Matchers.equalTo("should-fail"));
And attempting to build again:
mvn clean verify
...
[INFO] --- maven-surefire-plugin:2.22.1:test (unit-tests) @ springboot2-split-unit-integration-tests ---
[INFO]
[INFO] -------------------------------------------------------
[INFO] T E S T S
[INFO] -------------------------------------------------------
[INFO] Running com.asimio.demo.rest.DemoControllerTest
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 0.857 s <<< FAILURE! - in com.asimio.demo.rest.DemoControllerTest
[ERROR] shouldRetrieveAnEntity(com.asimio.demo.rest.DemoControllerTest) Time elapsed: 0.113 s <<< FAILURE!
java.lang.AssertionError:
Expected: "should-fail"
but: was "meh"
at com.asimio.demo.rest.DemoControllerTest.shouldRetrieveAnEntity(DemoControllerTest.java:37)
[INFO] Running com.asimio.demo.service.DefaultSomeBusinessServiceTest
[INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0 s - in com.asimio.demo.service.DefaultSomeBusinessServiceTest
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
...
The test
phase failed and prevented the build from running following phases. It’s a fail-fast approach. The artifact wasn’t built and integration tests didn’t run. Read more at Maven’s Build Default Lifecycle Reference.
6. CONCLUSION
It’s a good practice to add unit and integration tests when developing Enterprise applications. While a unit test suite should run in the order of milliseconds or seconds, integration tests take minutes if not hours.
Reseeding data, network traffic, starting Docker containers before executing a test or test suite will slow down your integration tests. It would make sense to split them when your test suites are large enough to have a faster feedback. Why? With a shorter build cycle, you get quicker feedback, allowing you to act faster, increasing your productivity.
Thanks for reading and sharing. If you found this post helpful and would like to receive updates when content like this gets published, sign up to the newsletter.
7. SOURCE CODE
Accompanying source code for this blog post can be found at:
8. REFERENCES
Recommend
-
10
Reporting Code Coverage using Maven and JaCoCo plugin1. INTRODUCTION Code coverage is a metric indicating which percentage of lines of code are executed when running automated tests.
-
7
6 Surefire Ways To Suck At Maintaining ProjectsJanuary 19th 2021 new story2
-
15
How do I resolve dependencies when using Maven to create a git plugin for Jenkins? advertisements I am trying to build and install the
-
8
Securing Your Business Data- 5 Surefire Measures You Can Rely On Data is the new fuel for any business. It helps you know your customers better so that you can fine-tune your long-term growth strategies. Even as custom...
-
3
5 Surefire Things That’ll Get You Targeted by Ransomware By Stefan Ionescu Published 1 day ago Ransomware is a serious threat t...
-
4
How do I run the GAE / J Convenience Store before performing Maven integration tests? advertisements I want to switch from
-
7
Separating Integration and Unit Tests with Maven, Sonar, Failsafe, and JaCoCo February 5, 2012 Goal: Execute the slow i...
-
11
Apache Maven Monday April 04, 2022 Apache Maven Surefire/Failsafe Plugin Version 3.0.0-M6 Released The Apache Maven team is...
-
7
Social media is a part of modern life, so, naturally, more movies should embrace it as central to the experiences of the characters in the m...
-
5
6 Market Analysis Steps to Building a Surefire Marketing StrategyNatalia ZhukovaSep 26, 202220 min readAs market comp...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK