I'm trying to generate unit test code coverage data for sonar for a multi-module maven project, and not getting correct results.
The project structure is similar to the following:
I am using the jacoco maven plugin to generate jacoco.exec
files, and the sonar maven plugin to analyse the code (including the jacoco.exec
files).
These files are generated during the process-tests
phase, as follows:
<properties>
<jacoco.report.path>${project.build.directory}/jacoco.exec</jacoco.report.path>
<sonar.jacoco.reportPath>${jacoco.report.path}</sonar.jacoco.reportPath>
</properties>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.4.201502262128</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<phase>process-test-classes</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${jacoco.report.path}</destFile>
</configuration>
</execution>
</executions>
</plugin>
When I run mvn clean install I can see that there is a jacoco.exec
file created for each module:
$ find . -name '*.exec'
./moduleA/target/jacoco.exec
./moduleB/moduleB1/target/jacoco.exec
./moduleB/moduleB2/target/jacoco.exec
./moduleC/target/jacoco.exec
When I run mvn sonar:sonar I see that the Jacoco sensor runs for all modules, but only seems to work with the first module. Subsequent modules show Coverage information was not collected
:
[INFO] [17:13:58.333] Sensor JaCoCoSensor
[INFO] [17:13:58.350] Analysing moduleA\target\jacoco.exec
[INFO] [17:13:58.374] No information about coverage per test.
[INFO] [17:13:58.374] Sensor JaCoCoSensor (done) | time=41ms
...
[INFO] [17:14:02.202] Sensor JaCoCoSensor
[INFO] [17:14:02.261] Analysing moduleB\moduleB1\target\jacoco.exec
[WARN] [17:14:02.334] Coverage information was not collected. Perhaps you forget to include debug information into compiled classes?
[INFO] [17:14:02.334] Sensor JaCoCoSensor (done) | time=132ms
...
I'm not sure why there's no coverage information in the second and subsequent modules, since maven-compiler-plugin
includes debug information by default, and to be safe I also ran mvn clean install -Dmaven.compiler.debug=true
but got the same results.
As a consequence of this, when I inspect the project in the sonar server it shows code coverage just for the first module: moduleA
. No code coverage information for the other modules is present.
Apparently the solution here is to generate only a single jacoco.exec
file, so that when the jacoco-maven-plugin
executes it appends the result for each module to that file, so that sonar can work its magic correctly.
Accordingly, I modified my parentPom/pom.xml
file as follows:
<properties>
<!-- single jacoco.exec file relative to root directory of the project -->
<jacoco.report.path>${session.executionRootDirectory}/code-coverage/jacoco.exec</jacoco.report.path>
<sonar.jacoco.reportPath>${jacoco.report.path}</sonar.jacoco.reportPath>
</properties>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.4.201502262128</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<phase>process-test-classes</phase>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${jacoco.report.path}</destFile>
<append>true</append> <!-- now appending to single jacoco.exec file -->
</configuration>
</execution>
</executions>
</plugin>
This means that after unit tests have run, the jacaco agent is invoked
Now when I run mvn clean install I see only one jacoco.exec
file:
$ find . -name '*.exec'
./code-coverage/target/jacoco.exec
But when I run mvn sonar:sonar the JaCoCoSensor does not seem to be invoked and the project on the sonar server has no code coverage at all.
What am I doing wrong here? How do I get sonar to analyse code coverage for all modules in my maven project?
Do I need to modify the maven-surefire-plugin
in some way?
I am using SonarQube 5.1, JDK 1.8, jacoco-maven-plugin 0.7.4.201502262128
JaCoCo sensor will only load coverage for the classes you covered in your module.
This means that if for some reason the jacoco.exec in your module B does not contain coverage information about the .class files of this module then it won't load any coverage (even if you covered classes in another module).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With