- Goals utilization
- Running the tests
- Jacoco Code Coverage Reports
- How to set up JaCoCo Plugin with Maven?
- Merge the data/exec files
- Generate the merged coverage report
- Add code coverage check
- How to set up JaCoCo Plugin with Maven for parallel execution?
Jacoco in action with Maven
Jacoco-Maven (abbreviation for Java Code Coverage) plugin is an open-source code coverage tool for Java. It creates code coverage reports and integrates well with IDEs(Integrated development environments) like Eclipse IDE.
The purpose of this small project (built on top of TestsExecution) is to utilize the Jacoco plugin for code coverage reports.
Goals utilization
Following goals of the Jacoco plugin can be used to generate coverage reports:
- The report goal can be used to generate the coverage report for unit tests only with little bit of config.
- The report-integration goal can be used to generate the coverage report for integration tests only with little bit of config.
- The merge goal can be used to generate the combined/merged coverage report for all the tests.
Individual reports for the code covered by unit tests as well as
integration tests will be generated. And then, a combined coverage report will also be generated to show the total coverage.
These generated coverage reports will then be included in the project reports through mvn site
.
Running the tests
See TestsExecution project
Jacoco Code Coverage Reports
- Code coverage reports for
- units tests are generated right after the execution of unit tests and can be found in
target/site/jacoco
directory. - integration tests are generated right after the execution of integration tests and can be found in
target/site/jacoco-it
directory. - Combined or merged report for both the unit and the integration tests' will also be generated right after the
execution of integration tests and can be found in
target/site/jacoco-merged
directory.
- units tests are generated right after the execution of unit tests and can be found in
- Once the reports are generated, point a browser at the output in any of the following directories to see:
- unit tests' coverage report:
target/site/jacoco/index.html
- integration tests' coverage report:
target/site/jacoco-it/index.html
- all tests' coverage report:
target/site/jacoco-merged/index.html
- unit tests' coverage report:
How to set up JaCoCo Plugin with Maven?
Here are the steps to integrate JaCoCo Maven plugin with a Maven project:
- Declare the Jacoco-Maven plugin in the pom.xml file as follows:
<build> <plugins> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco-maven-plugin.version}</version> </plugin> </plugins> </build>
- The above declaration won't be of much use without further configuration, so after the
version
tag, we add the executions tag. This tag prepares the properties or execution to point to the JaCoCo agent and is passed as a VM (in this case, JVM) argument. - The bare minimum for running simple unit tests (
mvn test
) is to set up a prepare-agent goal and report goal. The following config will run the JaCoCo report goal during the test phase of the build lifecycle:<plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>${jacoco-maven-plugin.version}</version> <executions> <execution> <id>before-unit-test-execution</id> <goals> <goal>prepare-agent</goal> </goals> </execution> <execution> <id>after-unit-test-execution</id> <phase>test</phase> <goals> <goal>report</goal> </goals> </execution> </executions> </plugin>
Prepare-agent goal:
The prepare-agent goal prepares the JaCoCo runtime agent to record the execution data. It records the number of lines executed, backtracked, etc. By default, the execution data is written to the filetarget/jacoco.exec
.
Report goal:
The report goal creates code coverage reports from the execution data recorded by the JaCoCo runtime agent. Since we have specified the phase property, so the reports will be created after the compilation of the test phase of the build lifecycle. By default, the execution data is read from the filetarget/jacoco.exec
, and the code coverage report is written
to the directory target/site/jacoco/index.html
.
Configuration for unit tests with custom paths
The following configuration inside the <id>before-unit-test-execution</id>
execution block, will set the data execution
file for the unit tests' coverage to be stored in target/jacoco-execs/ut.exec
file and we achieve that by overwriting
the surefire.jacoco.exec.file.name.arg
property used while running unit tests.
<configuration>
<destFile>target/jacoco-execs/ut.exec</destFile>
<propertyName>surefire.jacoco.exec.file.name.arg</propertyName>
</configuration>
We also need to tell where to find the data execution file while running the report goal, so we'll use
the following configuration in after-unit-test-execution
execution block. We've also set the outputDirectory
which
is an optional setting, and thats where the generated report will be stored.
<configuration>
<destFile>target/jacoco-execs/ut.exec</destFile>
<outputDirectory>${jacoco.ut.reporting.directory}</outputDirectory>
</configuration>
So, the full configuration for running the unit tests will look like this and we're all set as far as running and generating report for unit tests:
<execution>
<id>before-unit-test-execution</id>
<goals>
<goal>prepare-agent</goal>
</goals>
<configuration>
<destFile>target/jacoco-execs/ut.exec</destFile>
<propertyName>surefire.jacoco.exec.file.name.arg</propertyName>
</configuration>
</execution>
<execution>
<id>after-unit-test-execution</id>
<phase>test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<destFile>target/jacoco-execs/ut.exec</destFile>
<outputDirectory>${jacoco.ut.reporting.directory}</outputDirectory>
</configuration>
</execution>
Configuration for integration tests
Now we gonna need the exact same configuration for integration tests as follows:
<execution>
<id>before-integration-test-execution</id>
<phase>pre-integration-test</phase>
<goals>
<goal>prepare-agent-integration</goal>
</goals>
<configuration>
<destFile>target/jacoco-execs/it.exec</destFile>
<propertyName>failsafe.jacoco.exec.file.name.arg</propertyName>
</configuration>
</execution>
<execution>
<id>after-integration-test-execution</id>
<phase>post-integration-test</phase>
<goals>
<goal>report-integration</goal>
</goals>
<configuration>
<destFile>target/jacoco-execs/it.exec</destFile>
<outputDirectory>${jacoco.it.reporting.directory}</outputDirectory>
</configuration>
</execution>
In the above configuration, instead of using prepare-agent goal and report goal, we used prepare-agent-integration goal and report integration goal which are more related to the execution of integration tests.
The above config will run the JaCoCo report integration goal during the post-integration-test phase of the build lifecycle.
Merge the data/exec files
Add the following config after <id>after-integration-test-execution</id>
execution block:
<execution>
<id>merge-unit-and-integration</id>
<phase>post-integration-test</phase>
<goals>
<goal>merge</goal>
</goals>
<configuration>
<destFile>target/jacoco-execs/merged.exec</destFile>
<fileSets>
<fileSet>
<directory>target/jacoco-execs</directory>
<includes>
<include>ut.exec</include>
<include>it.exec</include>
</includes>
</fileSet>
</fileSets>
</configuration>
</execution>
In the above configuration, we've bound the merge goal to the post-integration-test phase
of the build lifecycle, which will merge the included exec
files into one single combined exec
file.
Generate the merged coverage report
Add the following config after <id>merge-unit-and-integration</id>
execution block:
<execution>
<id>create-merged-report</id>
<phase>post-integration-test</phase>
<goals>
<goal>report</goal>
</goals>
<configuration>
<dataFile>${jacoco.merged.exec}</dataFile>
<outputDirectory>${jacoco.merged.reporting.directory}</outputDirectory>
</configuration>
</execution>
In the above configuration, we've bound the report goal to the post-integration-test phase
of the build lifecycle, which will generate the combined coverage report from the provided exec
file.
Add code coverage check
Add the following config after <id>create-merged-report</id>
execution block:
<execution>
<id>jacoco-check</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>CLASS</element>
<excludes>
<exclude>*Test</exclude>
<exclude>*IT</exclude>
</excludes>
<limits>
<limit>
<counter>LINE</counter>
<value>COVEREDRATIO</value>
<minimum>${jacoco.minimum.line.coverage}</minimum>
</limit>
</limits>
</rule>
</rules>
<dataFile>${jacoco.merged.exec}</dataFile>
</configuration>
</execution>
In the above configuration, we've bound the check goal to the verify phase
of the build lifecycle, which will perform the verification checks according the specified rules
on the provided exec
file, and will fail the build if the checks are not met.
How to set up JaCoCo Plugin with Maven for parallel execution?
More configuration is required if we want to run the unit tests and integration tests parallel/simultaneously on multiple machines. For example, in CI/CD environment, we usually want parallel execution of jobs as much as possible to speed up the build process. So, in order to achieve that, let's first have separate execution data files for unit and integration tests.
To achieve the parallel execution, use the following commands:
- One job can run
mvn test -P ut
, which will generate a file namedjacoco.exec
orjacoco-ut.exec
, store or upload that file somewhere for later use - Another job can run
mvn integration-test -P it
, which will generate a file namedjacoco-it.exec
, store or upload that file somewhere for later use. NOTE: you might be wondering why we just didn't domvn verify -P nt
, that's because all the data files won't be present and hence the generated report won't be correct - Then in the report generation job:
- Download the
jacoco-ut.exec
andjacoco-it.exec
data files - Place them in the
target/jacoco-execs
directory or whichever directory you're using for the data files - Run the
mvn post-integration-test -P nt
ormvn verify -P nt
, and the generated reports will be there in thetarget/site
directory
- Download the