Jacoco Maven multi module project coverage
Asked Answered
V

6

38

Seems like there are couple of questions, which are quite old and things changed from Java 8 support of Jacoco.

My Project contains following structure

pom.xml
|
|
-----sub module A pom.xml
|
|
-----sub module B pom.xml
|
|
-----sub module C pom.xml

I have configured the main pom like this

Main POM.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.test</groupId>
    <artifactId>jacoco-multi</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>projectA</module>
        <module>projectB</module>
    </modules>

    <properties>
        <jacoco.version>0.5.7.201204190339</jacoco.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit-dep</artifactId>
            <version>4.10</version>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.hamcrest</groupId>
                    <artifactId>hamcrest-core</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>1.3.RC2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-library</artifactId>
            <version>1.3.RC2</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.jacoco</groupId>
                <artifactId>jacoco-maven-plugin</artifactId>
                <version>0.7.5.201505241946</version>
                <configuration>
                    <destFile>${project.basedir}/../target/jacoco.exec</destFile>
                    <append>true</append>
                </configuration>
                <executions>
                    <execution>
                        <id>jacoco-initialize</id>
                        <goals>
                            <goal>prepare-agent</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>jacoco-site</id>
                        <phase>package</phase>
                        <goals>
                            <goal>report</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-failsafe-plugin</artifactId>
                <version>2.16</version>
                <executions>
                    <execution>
                        <id>default-integration-test</id>
                        <goals>
                            <goal>integration-test</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.16</version>
            </plugin>
        </plugins>
    </build>

</project>

A Pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>jacoco-multi</artifactId>
        <groupId>com.test</groupId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>..</relativePath>
    </parent>
    <artifactId>projectA</artifactId>

    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <version>2.12</version>
                </plugin>

            </plugins>
        </pluginManagement>
    </build>

</project>

B pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
    <artifactId>jacoco-multi</artifactId>
    <groupId>com.test</groupId>
    <version>0.0.1-SNAPSHOT</version>
    <relativePath>..</relativePath>
</parent>
<artifactId>projectB</artifactId>

<dependencies>
    <dependency>
        <groupId>com.test</groupId>
        <artifactId>projectA</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
</dependencies>

<build>
    <pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.12</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

I am executing this command mvn clean package. I can see jacoco.exec is getting generated, however I am not able to see any HTML reports are being to verify the data.

Please help me with this. Another point is, my configuration is correct for Multi-Module projects?

Update

Identified issue. <destFile>${project.basedir}/../target/jacoco.exec</destFile> changed to <destFile>${project.basedir}/target/jacoco.exec</destFile>

Now it's generating reports for individual modules. Any idea how to generate consolidated report

Verine answered 12/10, 2015 at 10:21 Comment(4)
Did you look for the reports at target/site/jacoco-ut/index.html ?Pearse
@SaifAsif, yes. I can see only jacoco.exec file and no other folder being created under targetVerine
Pase the logs of mvn clean install here from the part when jacoco plugin kicks inPearse
@SaifAsif, please check the updated post. How do i generate consolidated report?Verine
N
43

JaCoCo version 0.7.7 can generate an aggregate coverage report from multiple Maven modules through a new goal jacoco:report-aggregate.

Nylanylghau answered 14/10, 2015 at 19:22 Comment(4)
Support for multi-module projects has been added as of version 0.7.7. To anyone looking for a bit of detail about usage with a Tycho build, I found this blog post by Lorenzo Bettini to be extremely helpful: JaCoCo Code Coverage and Report of multiple Eclipse plug-in projectsToscano
Summary: create a submodule exclusively for the aggregated report and make this submodule declare dependencies to the sibling submodules that it needs to aggregateChloramine
agree, for detailed steps: giri-tech.blogspot.com/2021/08/…Polarization
@Rogerio can you help me on this #75375632 ?Brainsick
P
11

After scanning many solutions I created a simple but complete Jacoco demo project showing:

  • Multi module project
  • Unit test (via mvn clean install)
  • Integration test (via mvn clean install -P integration-test)
  • Jacoco - test coverage ( both aggregate data file and aggregate reporting)
  • FindBugs - code quality

Enjoy the simple demo project. In this simple project the README.md file contains information you are looking for. An example is:

enter image description here

The simple demo project contains 3 branches:

  1. Master branch - containing the above functionality
  2. Multi-module-only-unit-tests - contains modules with only unit tests
  3. Multi-module-unit-tests-try2 - contains modules with unit tests, differently.
Pebbly answered 2/6, 2018 at 10:53 Comment(5)
I think it would help the answer to include some salient parts of the demo in the text of the answer here.Marya
Tx. I have added an example output and a hint where you easily can find info.Pebbly
@Pebbly can you help me on this #75375632 ?Brainsick
@Pebbly , I replied your github project on my project but any jacoco.exec file is created for any module . Maybe it depends because I use JUNIT 5 (jupiter engine and api ) ? Also I had to live JUNIT 4.1 dependency cause old Tests already present .Mclain
Here is the situation , for testing module i see the command to create exec file : argLine set to -javaagent:/home/devuser/.m2/repository/org/jacoco/org.jacoco.agent/0.7.9/org.jacoco.agent-0.7.9-runtime.jar=destfile=/home/devuser/work/SRPF/branches/S-RPF_3e4/testing/target/jacoco.exec but any exec was createdMclain
M
8

Follow below-mentioned instructions

  1. Create a new sub-project (usually called maven module). This will be used as report aggregator.
    parent pom will be like:
   <modules>
        <module>A</module>
        <module>B</module>
        <module>C</module>
        <module>ReportAggregator</module>
    </modules>
  1. In aggregator module pom- add other subprojects dependencies.
<dependency>
    <groupId>xyz</groupId>
    <artifactId>A</artifactId>
    <version>${project.version}</version>
</dependency>
  1. In aggregator module pom- configure jacoco plugin
<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.6</version>
    <executions>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <configuration>
                <dataFileIncludes>
                    <dataFileInclude>**/jacoco.exec</dataFileInclude>
                </dataFileIncludes>
                <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
  1. In aggregator module pom- configure surefire plugin as
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-surefire-plugin</artifactId>
    <version>3.0.0-M5</version>
    <configuration>
        <systemPropertyVariables>
            <jacoco-agent.destfile>**/jacoco.exec</jacoco-agent.destfile>
        </systemPropertyVariables>
    </configuration>
</plugin>
  1. (optional step) If anybody face warning/error like: Classes in bundle '*' do no match with execution data. For report generation, the same class files must be used as at runtime.**

Then add below mentioned lines in aggregator module pom

<plugin>
    <groupId>org.jacoco</groupId>
    <artifactId>jacoco-maven-plugin</artifactId>
    <version>0.8.6</version>
    <executions>
        <execution>
            <id>instrument-ut</id>
            <goals>
                <goal>instrument</goal>
            </goals>
        </execution>
        <execution>
            <id>restore-ut</id>
            <goals>
                <goal>restore-instrumented-classes</goal>
            </goals>
        </execution>
        <execution>
            <goals>
                <goal>prepare-agent</goal>
            </goals>
        </execution>
        <execution>
            <id>report-aggregate</id>
            <phase>verify</phase>
            <goals>
                <goal>report-aggregate</goal>
            </goals>
            <configuration>
                <dataFileIncludes>
                    <dataFileInclude>**/jacoco.exec</dataFileInclude>
                </dataFileIncludes>
                <outputDirectory>${project.reporting.outputDirectory}/jacoco-aggregate</outputDirectory>
            </configuration>
        </execution>
    </executions>
</plugin>
  1. run mvn clean install
Mantelet answered 9/12, 2020 at 21:24 Comment(5)
Do not run install, run verify only. Don't pollute your repo with snapshot versions.Mer
@BenjaminMarwell can you help me on this #75375632 ?Brainsick
@Mantelet why you wrote a reply a little bit different from tm1701 ? I can see differences since I download the whole project from github .For example the goal prepare-agent was originally put on pom (parent) project and you putted it in aggregator pom . why ?Mclain
Is there a way to pass multi module incl/excl classes in jacoco Java agent? Agent only takes a list of classes.Genuflection
@MehulParmar did you find a way to do it? I know that it's possible to add exclusion to agent configuration but you need to duplicate exclusion again. I didn't find a way how to use exists exclusion configuration for all dependencies.Renee
C
2

One problem in multimodule projects is caused, if the aggregator pom is used as parent pom for the modules either, like it is the case in the above example:

- parentAggregator pom
---sub module A pom.xml -> parentAggregator pom
---sub module B pom.xml -> parentAggregator pom
---sub module C pom.xml -> parentAggregator pom

In this case, the build order is:

- parentAggregator
- sub module A
- sub module B
- sub module C

which means, that the parent aggregator can not collect complete information. In my case a transfer of data into sonarQube by mvn sonar:sonar resulted in unexpected and uncomplete results.

Changing the module structure to:

- aggregator pom
-- parent pom
---sub module A pom.xml -> parent pom
---sub module B pom.xml -> parent pom
---sub module C pom.xml -> parent pom

will change the build order to:

- parent
- sub module A
- sub module B
- sub module C
- aggregator

In this case aggregator will be the last one and work with the results of the modules. In my case the results in SonarQube were like expected.

Cussed answered 19/1, 2017 at 13:47 Comment(0)
B
1

Run Coverage as... Junit for each module separately. Then create a launch group and add each of the run configurations. There is a popup "Launch Mode" with options Inherit, Profile, Coverage, Debug or Run. Choose Coverage for all of them. You probably also want to select "Wait until terminated".

You can now run all the coverage tests in one click. After they complete you need to go into the Coverage View and select merge sessions (double red/green bar) and merge them all into one report.

Broaddus answered 7/1, 2021 at 14:47 Comment(0)
K
0

For anyone want to find simple solution for merge Unit test and UI test in one report:

task jacocoUiTestReportAllModules(type: JacocoReport, dependsOn: ['testDebugUnitTest', 'createDebugCoverageReport']) {
group "Reports"
description "Generate Jacoco Instrumented Tests coverage reports for all modules"
reports {
    xml.enabled = true
    html.enabled = true
    html.destination file("${rootProject.buildDir}/coverage-report")
}
def javaClasses = []
def kotlinClasses = []
def javaSrc = []
def kotlinSrc = []
def execution = []
def fileFilter = ['**/R.class', '**/R$*.class', '**/BuildConfig.*', '**/Manifest*.*', '**/*Test*.*', 'android/**/*.*']
rootProject.subprojects.each { proj ->
    javaClasses << fileTree(dir: "$proj.buildDir/intermediates/javac/debug", excludes: fileFilter)
    kotlinClasses << fileTree(dir: "$proj.buildDir/tmp/kotlin-classes/debug", excludes: fileFilter)
    javaSrc << "$proj.projectDir/src/main/java"
    kotlinSrc << "$proj.projectDir/src/main/kotlin"
    execution << fileTree(dir: proj.buildDir, includes: [    'jacoco/testDebugUnitTest.exec',
            'outputs/code_coverage/debugAndroidTest/connected/**/*.ec'])
}
getSourceDirectories().setFrom(files([javaSrc, kotlinSrc]))
getClassDirectories().setFrom(files([javaClasses, kotlinClasses]))
getExecutionData().setFrom(execution)

doLast() {
    print "file://${reports.html.destination}/index.html"

}

}

Important: Apply plugin jacoco for module you want to coverage

Kampala answered 12/5, 2023 at 8:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.