Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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?

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.

Marvellous! This has worked. Finally! I think the magic missing vital incantation that I was missing was <append>true</append> – Stewart Apr 3, 2013 at 12:26 It works! I had to do a new mvn package before running mvn sonar:sonar to get the new report path generated. – thomasa88 Oct 14, 2014 at 9:31 According to example, "sonar.jacoco.itReportPath" property should be used to get merged results into "overall code coverage". Please update answer. – Yves Martin Apr 21, 2016 at 9:32 "sonar.dynamicAnalysis" is also deprecated: docs.sonarqube.org/display/SONAR/Release+4.3+Upgrade+Notes – Yves Martin Apr 21, 2016 at 9:33

NEW WAY SINCE VERSION 0.7.7

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>
        <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.

This works. The aggregate report shows the cumulative code coverage for all the modules. Did you ever try to view this cumulative report in Sonar ? I used sonar-qube to read jacoco.exec for individual reports, but with this report aggregate, i do not see an aggregated jacoco.exec in the report module. – Swetha V Feb 7, 2017 at 17:26 @SwethaV Any success in this? We're in the same position and need to find a way to generate the aggregated exec :) – Vinky Nov 8, 2017 at 16:16 We use sonar qube version 6.X which has its own test coverage page thus I don't need jacoco in there. For an older version we installed the cobertura plugin which also provided this functionality... – Lonzak Nov 9, 2017 at 18:42

Questions from the top of my head since that time I gone crazy with jacoco.

My application server (jBoss, Glassfish..) located in Iraq, Syria, whatever.. Is it possible to get multi-module coverage when running integration tests on it? Jenkins and Sonar are also on different servers.

Yes. You have to use jacoco agent that runs in mode output=tcpserver, jacoco ant lib. Basically two jars. This will give you 99% success.

How does jacoco agent works?

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.

Could I reset jacoco agent to start collecting execution data only since the time my test start?

Yes, for that purpose you need jacocoant.jar and ant build script located in your jenkins workspace.

So basically what I need from http://www.eclemma.org/jacoco/ is jacocoant.jar located in my jenkins workspace, and jacocoagent.jar located on my app server VM?

That's right.

I don't want to use ant, I've heard that jacoco maven plugin can do all the things too.

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.

What exactly does jacoco agent produce?

Only coverage data in .exec format. Sonar then can read it.

Does jacoco need to know where my java classes located are?

No, sonar does, but not jacoco. When you do mvn sonar:sonar path to classes comes into play.

So what about the ant script?

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

What should I do next?

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:

  • Invoke ant target jacocoReset to reset all previously collected data.
  • Run your tests
  • Invoke ant target jacocoReport to get report
  • If 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.

    How to push this report in sonar?

    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.

    I already have jacoco.exec in my `target` dir, `mvn sonar:sonar` ignores/removes it

    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).

    Maybe use ${maven.multiModuleProjectDirectory}/target/site/jacoco-aggregate/jacoco.xml instead of ../target/site/jacoco-aggregate/jacoco.xml Should work if projects are more than 1 level deep. Requires maven 3.3.1 or newer – Ulf Lindback Dec 25, 2021 at 10:46 Did not work for me. I have multimodule project, and submodules are independent of each other. After the suggested changes, I can see individual jacoco reports in each module, but the jacoco.xml of the aggregate module is empty. I am not using a separate aggregator module and using the parent module for this. – Sumit Feb 9, 2022 at 13:45 I have tried with a separate module for aggregating and there giving each submodule in dependency, It works fine and an aggregate report is generated. But the problem with giving dependency is that as per my release cycle versions of submodules keep on changing and these versions are different for every submodule. So it fails here as we cannot refer to submodule version in aggregate module as the submodule do not allow property sharing with each other. Any help here would be really great. Thanks – Sumit Feb 9, 2022 at 13:50

    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:

    |--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.

    I need to update this post at some stage as it's actually a little suboptimal. agent-for-it is only necessary when running the tests in TEST module but the current configuration has it running for every other module, where it has no value. The improvement would be to have agent-for-ut run in all other modules and agent-for-it only run in TEST. – markdsievers May 13, 2017 at 9:52

    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 only issues was, I had to run sonar with command, mvn org.sonarsource.scanner.maven:sonar-maven-plugin:3.4.0.905:sonar -DrunSonar due to A required class was missing while executing org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.1:sonar: org/sonar/batch/bootstrapper/IssueListener error. – Jimson James Feb 28, 2018 at 19:15 Don't use this magic. The given property is an implementation detail and shall not be relied upon. -- The Maven Developer Team – Michael-O Feb 13, 2019 at 18:41

    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>
                                <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>
                                <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>
                    Emphasis. Read my comment to another answer. It was the missing vital ingredient for me, not found in other docs.
    – Stewart
                    May 4, 2016 at 6:16
                    This works very well with Sonar Qube Version 6.5 (build 27846)  ... :D The Code Coverage will be correctly displayed.
    – udoline
                    Aug 17, 2018 at 13:01
    

    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>
                    <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>             
                <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>
                    Just one question here. what if the versions of our submodules are not fixed and keep on changing with the release. And they are non-consistent, meaning module1 is on 1.5 and module2 is on 3.6, so we cannot do a project. version or parent .project.version. Also, there are no ways POMs of submodules can interact and fetch dependency versions. Do you have any ideas on how can this be taken care of?
    – Sumit
                    Feb 9, 2022 at 12:29
    

    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

    Thanks for this; I'll take a look and let you know how it works out. Might not be this week though :) – Stewart Feb 20, 2013 at 14:13

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.