Reporting and Merging multi-module jacoco reports with report-aggregate

Reporting and Merging multi-module jacoco reports with report-aggregate

Generating a single JaCoCo coverage report for a multi-module Maven project can be tricky. If you’re struggling to aggregate results from sub-modules into one report, this guide will walk you through the solution step-by-step.


The Problem: Multi-Module JaCoCo Reports Not Merging

When using the jacoco-maven-plugin, you might encounter these issues:

  • Individual modules generate jacoco.exec files, but no combined report.
  • The report-aggregate goal runs too early, producing an empty report.
  • The root POM configuration conflicts with sub-module builds.

Why This Happens

The root cause is often incorrect plugin configuration order:

  1. Maven builds modules in the order listed in the root POM’s <modules> section.
  2. If the report-aggregate module runs before sub-modules, it can’t find their jacoco.exec files.
  3. The report-aggregate goal must execute after all sub-modules have been built and tested.

Step-by-Step Solution

1. Root POM Configuration

Configure prepare-agent in the root POM to instrument code during tests:

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.11</version>
      <executions>
        <execution>
          <id>prepare-agent</id>
          <goals>
            <goal>prepare-agent</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

2. Create a Dedicated Report Aggregator Module

Add a new module (e.g., report-aggregate) listed last in the root POM’s <modules>:

<modules>
  <module>sub-module1</module>
  <module>sub-module2</module>
  <module>report-aggregate</module>
</modules>

3. Configure the Aggregator Module’s POM

In report-aggregate/pom.xml:

  • Declare dependencies on all sub-modules.
  • Bind report-aggregate to the verify phase:
<dependencies>
  <dependency>
    <groupId>com.yourgroup</groupId>
    <artifactId>sub-module1</artifactId>
    <version>${project.version}</version>
  </dependency>
  <!-- Include other sub-modules -->
</dependencies>

<build>
  <plugins>
    <plugin>
      <groupId>org.jacoco</groupId>
      <artifactId>jacoco-maven-plugin</artifactId>
      <version>0.8.11</version>
      <executions>
        <execution>
          <id>report-aggregate</id>
          <phase>verify</phase>
          <goals>
            <goal>report-aggregate</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

Key Fixes and Best Practices

  1. Build Order Matters
    Ensure the aggregator module is built last so it accesses finalized jacoco.exec files.
  2. Avoid Redundant Configurations
    Do not include report-aggregate in the root POM’s plugin setup—it belongs only in the aggregator module.
  3. Verify Dependencies
    Sub-modules must be listed as <dependencies> (not <modules>) in the aggregator’s POM.
  4. Check Output Directory
    The merged report is generated at:
    report-aggregate/target/site/jacoco-aggregate/index.html.

Common Pitfalls

  • Incorrect Phase Binding: If report-aggregate runs during compile instead of verify, it skips test results.
  • Missing Dependencies: The aggregator module must depend on all sub-modules to ensure they’re built first.
  • Root POM Conflicts: Avoid defining report-aggregate in the root POM’s plugin section.

Final Output

After running mvn clean verify, open report-aggregate/target/site/jacoco-aggregate/index.html to see the merged coverage report.


Keywords

  • Merge JaCoCo reports multi-module Maven
  • Aggregate JaCoCo coverage report
  • Maven jacoco-maven-plugin report-aggregate
  • Fix empty JaCoCo report
  • Combine multiple jacoco.exec files

By following these steps, you’ll streamline coverage reporting for complex projects. For more details, refer to the official JaCoCo demo.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *