Unit And Integration Test Reports For Maven Projects In SonarQube 4.5.1
Since SonarQube 4.2. the test report isn't generated by the Sonar Maven Plugin during a Maven build (see SonarQube's blog post) . Therefore, the test report has to be generated by another plugin before Sonar Maven Plugin collects the information for the SonarQube server. Here, Jacoco Maven Plugin can help. It has the possibility to generate test report that are understandable for SonarQube. Jacoco Maven Plugin goes one step further, it has the possibility to generate a test report for integration test.
In the following sections, a solution is presented that meets following criteria:
- Maven is used as build tool.
- The project can be a multi module project.
- Unit tests and integration tests are parts of each module. Here, integration tests are tests that test the integration between classes in a module.
- Test reports are separate in unit test report and integration test report.
The road map for the next section is that firstly the Maven project structure is shown for the separation of unit and integration tests. Then the Maven project configuration is shown for having separate unit test runs and integration test runs. After that, we have a look on the Maven project configuration for the test report generation separated in unit test and integration test. At the end, SonarQube's configuration is shown for the test report visualization in the SonarQube's dashboard.
Maven Project Structure
At first, we look at how a default Maven project structure looks like for a single module project.
1my-app
2├── pom.xml
3├── src
4│ ├── main
5│ │ └── java
6│ └── test
7│ └── java
The directory src/main/java
contains the production source code and the directory src/test/java
contains the test source code. We could put unit tests and integration tests together in this directory. But we want to separate these two types of tests in separate directories. Therefore, we add a new directory called src/it/java.
Then unit tests are put in the directory src/test/java
and the integration tests are put in the directory src/it/java,
so the new project structure looks like the following one.
1my-app
2├── pom.xml
3├── src
4│ ├── it
5│ │ └── java
6│ ├── main
7│ │ └── java
8│ └── test
9│ └── java
Unit And Integration Test Runs
Fortunately, the unit test run configuration is a part of the Maven default project configuration. Maven runs these tests automatically if following criteria are met:
- The tests are in the directory
src/test/java
and - the test class name either starts with
Test
or ends withTest
orTestCase.
Maven runs these tests during the Maven's build lifecylce phase test.
The integration test run configuration has to be done manually. It exists Maven plugins that can help. We want that the following criteria are met:
- integration tests are stored in the directory
src/it/java
and - the integration test class name either starts
IT
or ends withIT
orITCase
and - integrations tests runs during the Maven's build lifecycle phase
integration-test.
Firstly, Maven has to know that it has to include the directory src/it/java
to its test class path. Here, the Build Helper Maven Plugin can help. It adds the directory src/it/java
to the test class path.
1 <plugin>
2 <groupId>org.codehaus.mojo</groupId>
3 <artifactId>build-helper-maven-plugin</artifactId>
4 <version>1.8</version>
5 <executions>
6 <execution>
7 <id>add-test-source</id>
8 <phase>process-test-sources</phase>
9 <goals>
10 <goal>add-test-source</goal>
11 </goals>
12 <configuration>
13 <sources>
14 <source>src/it/java</source>
15 </sources>
16 </configuration>
17 </execution>
18 <execution>
19 <id>add-test-resources</id>
20 <phase>generate-test-resources</phase>
21 <goals>
22 <goal>add-test-resource</goal>
23 </goals>
24 <configuration>
25 <resources>
26 <resource>
27 <directory>src/it/resources</directory>
28 </resource>
29 </resources>
30 </configuration>
31 </execution>
32 </executions>
33 </plugin>
The above code snippet has to be inserted into the section <project><build><plugins>
in the project root pom.
Maven's build lifecycle contains a phase called integration-test.
In this phase, we want to run the integration test. Therefore, we bind the Maven Failsafe Plugin to the phase integration-test:
1 <plugin>
2 <groupId>org.apache.maven.plugins</groupId>
3 <artifactId>maven-failsafe-plugin</artifactId>
4 <version>2.13</version>
5 <configuration>
6 <encoding>${project.build.sourceEncoding}</encoding>
7 </configuration>
8 <executions>
9 <execution>
10 <id>failsafe-integration-tests</id>
11 <phase>integration-test</phase>
12 <goals>
13 <goal>integration-test</goal>
14 <goal>verify</goal>
15 </goals>
16 </execution>
17 </executions>
18 </plugin>
Again, the above code snippet also has to be inserted into the section <project><build><plugins>
in the project root pom. Then Maven Failsafe Plugin runs the integration tests automatically, when their class name either starts with IT
or ends with IT
or ITCase.
Test Report Generation
We want to use the Jacoco Maven Plugin for the test report generation. It should generate two test reports, one for the unit test and one for the integration tests. Therefore, the plugin has to two separated agents, that have to be prepared. Then they generate the report during the test runs. The Maven's build lifecycle contains own phases for preparation before the test phases (test
and integration-test
). The preparation phase for the test
phase is called process-test-classes
and the preparation phase for integration-test
phase is called pre-integration-test
. In these two phases we bind the Jacoco Maven Plugin, so the configuration of this plugin looks like the following code snippet (Again, it is a part of the section <project><build><plugins>
):
1 <plugin>
2 <groupId>org.jacoco</groupId>
3 <artifactId>jacoco-maven-plugin</artifactId>
4 <version>0.7.2.201409121644</version>
5 <executions>
6 <execution>
7 <configuration>
8 <destFile>${sonar.jacoco.reportPath}</destFile>
9 </configuration>
10 <id>pre-test</id>
11 <phase>process-test-classes</phase>
12 <goals>
13 <goal>prepare-agent</goal>
14 </goals>
15 </execution>
16 <!-- we want to execute jacoco:prepare-agent-integration in test phase,
17 but before executing maven failsafe plugin -->
18 <execution>
19 <configuration>
20 <destFile>${sonar.jacoco.itReportPath}</destFile>
21 </configuration>
22 <id>pre-itest</id>
23 <phase>pre-integration-test</phase>
24 <goals>
25 <goal>prepare-agent-integration</goal>
26 </goals>
27 </execution>
28 </executions>
29 </plugin>
The configuration element destFile
is the path to the location, where the test reports should be stored. It is important to use the properties ${sonar.jacoco.reportPath}
and ${sonar.jacoco.itReportPath}
. These properties are used by SonarQube to find the test reports for the visualization.
Now, we can run the goal mvn install
and our project is built inclusive unit and integration test and inclusive generating two test reports.
SonarQube Test Report Visualization
Now, we want to visualize our test reports in SonarQube. Therefore, we have to run the Sonar Maven 3 Plugin (command mvn sonar:sonar
) in our project after a successful build.
When we open our project in the SonarQube dashboard, we see only the report for the unit test per module. The reason is that the report visualization of the integration test has to be configured in SonarQube, separately. These configuration steps are described in the SonarQube documentation very well.
Summary
This blog describes how to generate test reports for unit and integration test during a Maven build. On GitHub, I host a sample project that demonstrate all configuration steps. As technical environment I use
- Maven 3.2.5
- Maven Plugins:
- Maven Surefire Plugin
- Maven Failsafe Plugin
- Build Helper Maven Plugin
- Jacoco Maven Plugin
- Sonar Maven 3 Plugin
- SonarQube 4.5.1
- Java 7
Links
- SonarQube's blog post Unit Test Execution in SonarQube
- Jacoco Maven plugin project site
- Introduction to Maven's build lifecycle
- Maven Failsafe Plugin project site
- Build Helper Maven Plugin project site
- SonarQube documentation about Code Coverage by Integration Tests for Java Project
- A sample Maven project on GitHub