I've searched up and down the internet for this one. There's lots of half-answers out there, to do with Maven properties such as ${sonar.jacoco.reportPath}
, or org.jacoco:jacoco-maven-plugin:prepare-agent
or setting maven-surefire-plugin
argLine
with -javaagent
.
Some how, none of these answers, either on their own, or in combination, are producing what I'm after: A coverage report which shows a class as covered if it is used in tests higher up the stack, such as entities being used by DAOs, even though it was not fully covered by tests in its own module.
Is there a definitive config somewhere, to achieve this, please?
To get code coverage reports in a Maven project, we first need to set up the JaCoCo Maven plugin for that project. By integrating the JaCoCo plugin, the results of the code coverage analysis can be reviewed as an HTML report. The current version of the JaCoCo-Maven plugin can be downloaded from the MVN Repository.
Why does the coverage report not show line coverage figures? JaCoCo is based on class files analysis. To calculate line coverage class files must contain line number attributes. For this your code must be compiled with debug information.
JaCoCo vs SonarQube: What are the differences? JaCoCo: A code coverage library for Java. It is a free code coverage library for Java, which has been created based on the lessons learned from using and integration existing libraries for many years; SonarQube: Continuous Code Quality.
I was in the same situation as you, the half answers scattered throughout the Internet were quite annoying, since it seemed that many people had the same issue, but no one could be bothered to fully explain how they solved it.
The Sonar docs refer to a GitHub project with examples that are helpful. What I did to solve this was to apply the integration tests logic to regular unit tests (although proper unit tests should be submodule specific, this isn't always the case).
In the parent pom.xml, add these properties:
<properties>
<!-- Sonar -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
</properties>
This will make Sonar pick up unit testing reports for all submodules in the same place (a target folder in the parent project). It also tells Sonar to reuse reports ran manually instead of rolling its own. We just need to make jacoco-maven-plugin run for all submodules by placing this in the parent pom, inside build/plugins:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.6.0.201210061924</version>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
</configuration>
<executions>
<execution>
<id>agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
destFile
places the report file in the place where Sonar will look for it and append
makes it append to the file rather than overwriting it. This will combine all JaCoCo reports for all submodules in the same file.
Sonar will look at that file for each submodule, since that's what we pointed him at above, giving us combined unit testing results for multi module files in Sonar.
Since Version 0.7.7 there is a new way to create an aggregated report:
You create a separate 'report' project which collects all the necessary reports (Any goal in the aggregator project is executed before its modules therefore it can't be used).
aggregator pom
|- parent pom
|- module a
|- module b
|- report module
The root pom looks like this (don't forget to add the new report module under modules):
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
The poms from each sub module doesn't need to be changed at all. The pom from the report module looks like this:
<!-- Add all sub modules as dependencies here -->
<dependencies>
<dependency>
<module a>
</dependency>
<dependency>
<module b>
</dependency>
...
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
<executions>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
A full exmple can be found here.
Questions from the top of my head since that time I gone crazy with jacoco.
Yes. You have to use jacoco agent that runs in mode output=tcpserver
, jacoco ant lib. Basically two jar
s. This will give you 99% success.
You append a string
-javaagent:[your_path]/jacocoagent.jar=destfile=/jacoco.exec,output=tcpserver,address=*
to your application server JAVA_OPTS and restart it. In this string only [your_path]
have to be replaced with the path to jacocoagent.jar, stored(store it!) on your VM where app server runs. Since that time you start app server, all applications that are deployed will be dynamically monitored and their activity (meaning code usage) will be ready for you to get in jacocos .exec format by tcl request.
Yes, for that purpose you need jacocoant.jar and ant build script located in your jenkins workspace.
That's right.
That's not right, jacoco maven plugin can collect unit test data and some integration tests data(see Arquillian Jacoco), but if you have for example rest assured tests as a separated build in jenkins, and want to show multi-module coverage, I can't see how maven plugin can help you.
Only coverage data in .exec
format. Sonar then can read it.
No, sonar does, but not jacoco. When you do mvn sonar:sonar
path to classes comes into play.
It has to be presented in your jenkins workspace. Mine ant script, I called it jacoco.xml
looks like that:
<project name="Jacoco library to collect code coverage remotely" xmlns:jacoco="antlib:org.jacoco.ant">
<property name="jacoco.port" value="6300"/>
<property name="jacocoReportFile" location="${workspace}/it-jacoco.exec"/>
<taskdef uri="antlib:org.jacoco.ant" resource="org/jacoco/ant/antlib.xml">
<classpath path="${workspace}/tools/jacoco/jacocoant.jar"/>
</taskdef>
<target name="jacocoReport">
<jacoco:dump address="${jacoco.host}" port="${jacoco.port}" dump="true" reset="true" destfile="${jacocoReportFile}" append="false"/>
</target>
<target name="jacocoReset">
<jacoco:dump address="${jacoco.host}" port="${jacoco.port}" reset="true" destfile="${jacocoReportFile}" append="false"/>
<delete file="${jacocoReportFile}"/>
</target>
</project>
Two mandatory params you should pass when invoking this script
-Dworkspace=$WORKSPACE
use it to point to your jenkins workspace and -Djacoco.host=yourappserver.com
host without http://
Also notice that I put my jacocoant.jar
to ${workspace}/tools/jacoco/jacocoant.jar
Did you start your app server with jacocoagent.jar?
Did you put ant script and jacocoant.jar in your jenkins workspace?
If yes the last step is to configure a jenkins build. Here is the strategy:
jacocoReset
to reset all previously collected data.jacocoReport
to get reportIf everything is right, you will see it-jacoco.exec
in your build workspace.
Look at the screenshot, I also have ant
installed in my workspace in $WORKSPACE/tools/ant
dir, but you can use one that is installed in your jenkins.
Maven sonar:sonar
will do the job (don't forget to configure it), point it to main pom.xml so it will run through all modules. Use sonar.jacoco.itReportPath=$WORKSPACE/it-jacoco.exec
parameter to tell sonar where your integration test report is located. Every time it will analyse new module classes, it will look for information about coverage in it-jacoco.exec
.
By default mvn sonar:sonar
does clean
and deletes your target dir, use sonar.dynamicAnalysis=reuseReports
to avoid it.
I found another solution for new Sonar versions where JaCoCo's binary report format (*.exec) was deprecated and the preferred format is XML (SonarJava 5.12 and higher). The solution is very simple and similar to the previous solution with *.exec reports in parent directory from this topic: https://stackoverflow.com/a/15535970/4448263.
Assuming that our project structure is:
moduleC - aggregate project's pom
|- moduleA - some classes without tests
|- moduleB - some classes depending from moduleA and tests for classes in both modules: moduleA and moduleB
You need following maven build plugin configuration in aggregate project's pom:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<id>prepare-and-report</id>
<goals>
<goal>prepare-agent</goal>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
<configuration>
<outputDirectory>${project.basedir}/../target/site/jacoco-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Then build project with maven:
mvn clean verify
And for Sonar you should set property in administration GUI:
sonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml
or using command line:
mvn sonar:sonar -Dsonar.coverage.jacoco.xmlReportPaths=target/site/jacoco/jacoco.xml,../target/site/jacoco-aggregate/jacoco.xml
Description
This creates binary reports for each module in default directories: target/jacoco.exec
. Then creates XML reports for each module in default directories: target/site/jacoco/jacoco.xml
. Then creates an aggregate report for each module in custom directory ${project.basedir}/../target/site/jacoco-aggregate/
that is relative to parent directory for each module. For moduleA and moduleB this will be common path moduleC/target/site/jacoco-aggregate/
.
As moduleB depends on moduleA, moduleB will be built last and its report will be used as an aggregate coverage report in Sonar for both modules A and B.
In addition to the aggregate report, we need a normal module report as JaCoCo aggregate reports contain coverage data only for dependencies.
Together, these two types of reports providing full coverage data for Sonar.
There is one little restriction: you should be able to write a report in the project's parent directory (should have permission). Or you can set property jacoco.skip=true
in root project's pom.xml (moduleC) and jacoco.skip=false
in modules with classes and tests (moduleA and moduleB).
I'll post my solution as it it subtly different from others and also took me a solid day to get right, with the assistance of the existing answers.
For a multi-module Maven project:
ROOT
|--WAR
|--LIB-1
|--LIB-2
|--TEST
Where the WAR
project is the main web app, LIB
1 and 2 are additional modules the WAR
depends on and TEST
is where the integration tests live.
TEST
spins up an embedded Tomcat instance (not via Tomcat plugin) and runs WAR
project and tests them via a set of JUnit tests.
The WAR
and LIB
projects both have their own unit tests.
The result of all this is the integration and unit test coverage being separated and able to be distinguished in SonarQube.
ROOT pom.xml
<!-- Sonar properties-->
<sonar.jacoco.itReportPath>${project.basedir}/../target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.jacoco.reportPath>${project.basedir}/../target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<!-- build/plugins (not build/pluginManagement/plugins!) -->
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<id>agent-for-ut</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${sonar.jacoco.reportPath}</destFile>
</configuration>
</execution>
<execution>
<id>agent-for-it</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${sonar.jacoco.itReportPath}</destFile>
</configuration>
</execution>
</executions>
</plugin>
WAR
, LIB
and TEST
pom.xml
will inherit the the JaCoCo plugins execution.
TEST pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
<configuration>
<skipTests>${skip.tests}</skipTests>
<argLine>${argLine} -Duser.timezone=UTC -Xms256m -Xmx256m</argLine>
<includes>
<includes>**/*Test*</includes>
</includes>
</configuration>
</execution>
</executions>
</plugin>
I also found Petri Kainulainens blog post 'Creating Code Coverage Reports for Unit and Integration Tests With the JaCoCo Maven Plugin' to be valuable for the JaCoCo setup side of things.
There is a way to accomplish this. The magic is to create a combined jacoco.exec file. And with maven 3.3.1 there is an easy way to get this. Here my profile:
<profile>
<id>runSonar</id>
<activation>
<property>
<name>runSonar</name>
<value>true</value>
</property>
</activation>
<properties>
<sonar.language>java</sonar.language>
<sonar.host.url>http://sonar.url</sonar.host.url>
<sonar.login>tokenX</sonar.login>
<sonar.jacoco.reportMissing.force.zero>true</sonar.jacoco.reportMissing.force.zero>
<sonar.jacoco.reportPath>${jacoco.destFile}</sonar.jacoco.reportPath>
<jacoco.destFile>${maven.multiModuleProjectDirectory}/target/jacoco_analysis/jacoco.exec</jacoco.destFile>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<append>true</append>
<destFile>${jacoco.destFile}</destFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.2</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.8</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</profile>
If you add this profile to your parent pom and call mvn clean install sonar:sonar -DrunSonar
you get the complete coverage.
The magic here is maven.multiModuleProjectDirectory
. This folder is always the folder where you started your maven build.
The configuration I use in my parent level pom where I have separate unit and integration test phases.
I configure the following properties in the parent POM Properties
<maven.surefire.report.plugin>2.19.1</maven.surefire.report.plugin>
<jacoco.plugin.version>0.7.6.201602180812</jacoco.plugin.version>
<jacoco.check.lineRatio>0.52</jacoco.check.lineRatio>
<jacoco.check.branchRatio>0.40</jacoco.check.branchRatio>
<jacoco.check.complexityMax>15</jacoco.check.complexityMax>
<jacoco.skip>false</jacoco.skip>
<jacoco.excludePattern/>
<jacoco.destfile>${project.basedir}/../target/coverage-reports/jacoco.exec</jacoco.destfile>
<sonar.language>java</sonar.language>
<sonar.exclusions>**/generated-sources/**/*</sonar.exclusions>
<sonar.core.codeCoveragePlugin>jacoco</sonar.core.codeCoveragePlugin>
<sonar.coverage.exclusions>${jacoco.excludePattern}</sonar.coverage.exclusions>
<sonar.dynamicAnalysis>reuseReports</sonar.dynamicAnalysis>
<sonar.jacoco.reportPath>${project.basedir}/../target/coverage-reports</sonar.jacoco.reportPath>
<skip.surefire.tests>${skipTests}</skip.surefire.tests>
<skip.failsafe.tests>${skipTests}</skip.failsafe.tests>
I place the plugin definitions under plugin management.
Note that I define a property for surefire (surefireArgLine) and failsafe (failsafeArgLine) arguments to allow jacoco to configure the javaagent to run with each test.
Under pluginManagement
<build>
<pluginManagment>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<fork>true</fork>
<meminitial>1024m</meminitial>
<maxmem>1024m</maxmem>
<compilerArgument>-g</compilerArgument>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
<encoding>${project.build.sourceEncoding}</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<forkCount>4</forkCount>
<reuseForks>false</reuseForks>
<argLine>-Xmx2048m ${surefireArgLine}</argLine>
<includes>
<include>**/*Test.java</include>
</includes>
<excludes>
<exclude>**/*IT.java</exclude>
</excludes>
<skip>${skip.surefire.tests}</skip>
</configuration>
</plugin>
<plugin>
<!-- For integration test separation -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.19.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.19.1</version>
</dependency>
</dependencies>
<configuration>
<forkCount>4</forkCount>
<reuseForks>false</reuseForks>
<argLine>${failsafeArgLine}</argLine>
<includes>
<include>**/*IT.java</include>
</includes>
<skip>${skip.failsafe.tests}</skip>
</configuration>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
<execution>
<id>verify</id>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<!-- Code Coverage -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<configuration>
<haltOnFailure>true</haltOnFailure>
<excludes>
<exclude>**/*.mar</exclude>
<exclude>${jacoco.excludePattern}</exclude>
</excludes>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.check.lineRatio}</minimum>
</limit>
<limit>
<counter>BRANCH</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.check.branchRatio}</minimum>
</limit>
</limits>
</rule>
<rule>
<element>METHOD</element>
<limits>
<limit>
<counter>COMPLEXITY</counter>
<value>TOTALCOUNT</value>
<maximum>${jacoco.check.complexityMax}</maximum>
</limit>
</limits>
</rule>
</rules>
</configuration>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${jacoco.destfile}</destFile>
<append>true</append>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
<outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
<skip>${skip.surefire.tests}</skip>
</configuration>
</execution>
<execution>
<id>pre-integration-test</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${jacoco.destfile}</destFile>
<append>true</append>
<propertyName>failsafeArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>report-integration</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
<outputDirectory>${sonar.jacoco.reportPath}</outputDirectory>
<skip>${skip.failsafe.tests}</skip>
</configuration>
</execution>
<!-- Disabled until such time as code quality stops this tripping
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<dataFile>${jacoco.destfile}</dataFile>
</configuration>
</execution>
-->
</executions>
</plugin>
...
And in the build section
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<!-- for unit test execution -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
</plugin>
<plugin>
<!-- For integration test separation -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
<plugin>
<!-- For code coverage -->
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
</plugin>
....
And in the reporting section
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven.surefire.report.plugin}</version>
<configuration>
<showSuccess>false</showSuccess>
<alwaysGenerateFailsafeReport>true</alwaysGenerateFailsafeReport>
<alwaysGenerateSurefireReport>true</alwaysGenerateSurefireReport>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco.plugin.version}</version>
<configuration>
<excludes>
<exclude>**/*.mar</exclude>
<exclude>${jacoco.excludePattern}</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</reporting>
As Sonars sonar.jacoco.reportPath
, sonar.jacoco.itReportPath
and sonar.jacoco.reportPaths
have all been deprecated, you should use sonar.coverage.jacoco.xmlReportPaths
now. This also has some impact if you want to configure a multi module maven project with Sonar and Jacoco.
As @Lonzak pointed out, since Sonar 0.7.7, you can use Sonars report aggragation goal. Just put in you parent pom the following dependency:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.5</version>
<executions>
<execution>
<id>report</id>
<goals>
<goal>report-aggregate</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
As current versions of the jacoco-maven-plugin are compatible with the xml-reports, this will create for every module in it's own target folder a site/jacoco-aggregate folder containing a jacoco.xml
file.
To let Sonar combine all the modules, use following command:
mvn -Dsonar.coverage.jacoco.xmlReportPaths=full-path-to-module1/target/site/jacoco-aggregate/jacoco.xml,module2...,module3... clean verify sonar:sonar
To keep my answer short and precise, I did not mention the maven-surefire-plugin
and
maven-failsafe-plugin
dependencies. You can just add them without any other configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
<executions>
<execution>
<id>integration-test</id>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.jacoco.reportPath>${user.dir}/target/jacoco.exec</sonar.jacoco.reportPath>
<sonar.jacoco.itReportPath>${user.dir}/target/jacoco-it.exec</sonar.jacoco.itReportPath>
<sonar.exclusions>
file:**/target/generated-sources/**,
file:**/target/generated-test-sources/**,
file:**/target/test-classes/**,
file:**/model/*.java,
file:**/*Config.java,
file:**/*App.java
</sonar.exclusions>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.9</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.reportPath}</destFile>
<append>true</append>
<propertyName>surefire.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-prepare-agent-integration</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${sonar.jacoco.itReportPath}</destFile>
<append>true</append>
<propertyName>failsafe.argLine</propertyName>
</configuration>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-report-integration</id>
<goals>
<goal>report-integration</goal>
</goals>
</execution>
</executions>
</plugin>
You can call a ant task called merge on maven, to put all coverage files (*.exec) together in the same file.
If you are run unit tests use the phase prepare-package, if you run integration test so use post-integration-test.
This site has an example to how call jacoco ant task in maven project
You can use this merged file on sonar.
to have unit-testing AND integration-testing you can use maven-surefire-plugin and maven-failsafe-plugin with restricted includes/excludes. I was playing with CDI while getting in touch with sonar/jacoco, so i ended up in this project:
https://github.com/FibreFoX/cdi-sessionscoped-login/
Maybe it helps you a little bit. in my pom.xml i use "-javaagent" implicit by setting the argLine-option in the configuration-section of the specified testing-plugins. Explicit using ANT in MAVEN projects is something i would not give a try, for me its to much mixing two worlds.
I only have a single-module maven project, but maybe it helps you to adjust yours to work.
note: maybe not all maven-plugins are up2date, maybe some issues are fixed in later versions
This sample works very well for me :
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.2</version>
<executions>
<execution>
<id>pre-unit-test</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</destFile>
<propertyName>surefireArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>pre-integration-test</id>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>${project.build.directory}/coverage-reports/jacoco-it.exec</destFile>
<!--<excludes>
<exclude>com.asimio.demo.rest</exclude>
<exclude>com.asimio.demo.service</exclude>
</excludes>-->
<propertyName>testArgLine</propertyName>
</configuration>
</execution>
<execution>
<id>post-integration-test</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco-it.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-it</outputDirectory>
</configuration>
</execution>
<execution>
<id>post-unit-test</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/jacoco-ut.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-ut</outputDirectory>
</configuration>
</execution>
<execution>
<id>merge-results</id>
<phase>verify</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<directory>${project.build.directory}/coverage-reports</directory>
<includes>
<include>*.exec</include>
</includes>
</fileSet>
</fileSets>
<destFile>${project.build.directory}/coverage-reports/aggregate.exec</destFile>
</configuration>
</execution>
<execution>
<id>post-merge-report</id>
<phase>verify</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${project.build.directory}/coverage-reports/aggregate.exec</dataFile>
<outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
<configuration>
<argLine>${surefireArgLine}</argLine>
<!--<skipTests>${skip.unit.tests}</skipTests>-->
<includes>
<include>**/*Test.java</include>
<!--<include>**/*MT.java</include>
<include>**/*Test.java</include>-->
</includes>
<!-- <skipTests>${skipUTMTs}</skipTests>-->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.12.4</version>
<configuration>
<!--<skipTests>${skipTests}</skipTests>
<skipITs>${skipITs}</skipITs>-->
<argLine>${testArgLine}</argLine>
<includes>
<include>**/*IT.java</include>
</includes>
<!--<excludes>
<exclude>**/*UT*.java</exclude>
</excludes>-->
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
As stated in the Jacoco Wiki, you could also generate a new reporting-module:
Strategy: Module with Dependencies: The problems with aggregator projects can be solved with an extra "reporting" module. In a multi-module Maven project a separate module is defined that does not contribute actual content but creates a combined coverage report. It defines a dependency to all the modules that should be included in the combined report. The "reporting" module would be built after its dependencies and have access to the exec files as well as class and source files from projects it depends on. This strategy seems to work best with the current Maven architecture. From a user's perspective one could argue that such a separate module would bloat the build definition. Or, that the separate module cannot have any submodules from which it could consume exec or class files. However, compared to the other strategies these drawbacks seem rather minor and can be handled in a consistent manner.
This is especially helpful if your modularisation is more complex than one parent with some child modules.
Your reporting pom could look something like:
<dependencies>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module1</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.sonarqube</groupId>
<artifactId>module2</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<executions>
<execution>
<id>report</id>
<goals>
<goal>report-aggregate</goal>
</goals>
<phase>verify</phase>
</execution>
</executions>
</plugin>
</plugins>
</build>
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