Multi-Module Test Reporting with Gradle 7.x

2022 11 02 head

I love Gradle as the building tool for all my Java projects.

But sometimes I was discouraged about how spotty or cumbersome the support for a multi-module project is.

I struggled for years to generate test and code overage reports over modules included in a Gradle Build Tool project.

Gradle finally provides a better approach to generating aggregated test and code coverage reports over multiple modules belonging to the same project. The solution is a huge improvement against the previous quite cumbersome approach described in [1].

Two plugins nicely solve this daunting problem for all Java developers preferring Gradle Build Tool over Maven.

I hope similar solutions will be provided for static code analyzers such as SpotBugs, PMD, or Checkstyle.

Selected Approach

We use the documented approach to defining a separate module to generate the aggregation reports.

plugins {                                           (1)
    id 'test-report-aggregation'
    id 'jacoco-report-aggregation'
}

dependencies {                                      (2)
    testReportAggregation project(':net.tangly.bdd')
    testReportAggregation project(':net.tangly.commons')
    testReportAggregation project(':net.tangly.core')
    testReportAggregation project(':net.tangly.dev')

    jacocoAggregation project(':net.tangly.bdd')
    jacocoAggregation project(':net.tangly.commons')
    jacocoAggregation project(':net.tangly.core')
    jacocoAggregation project(':net.tangly.dev')
 }

reporting {                                         (3)
    reports {
        testAggregateTestReport(AggregateTestReport) {
            testType = TestSuiteType.UNIT_TEST
        }
        testCodeCoverageReport(JacocoCoverageReport) {
            testType = TestSuiteType.UNIT_TEST
        }
    }
}
1 Load the plugin for the test aggregation report and the test coverage aggregation report.
2 Declare the modules which results should be aggregated. We have to declare the same subprojects for each plugin separately.
3 Configure the aggregation reports.

We call the following goals to generate the aggregation results:

./gradlew testAggregateTestReport (1)
./gradlew testCodeCoverageReport  (2)
1 Generates an aggregate report over all unit tests. Run before the Gradle test.
2 Generates a code coverage aggregate report over all unit tests. Run first gradle jacocoTestReport.

Learnings

Gradle provides test results aggregation and test coverage aggregation as two separate plugins. The drawback is that we have to configure both plugins with the same information.

The plugins make the assumption that modules are called from an application subproject. The scenario of a mono repository containing a set of libraries is not covered.

We would encourage the plugin authors to provide a default configuration option based on the Gradle settings defined in settings.gradle. The modules are defined in the file and could be retrieved by the plugin using the Gradle API.

Apply the cardinal rule of good user interface design. Do not ask the user to give information already available to the application.

The new plugins are a huge simplification over the cumbersome and almost magic statements we needed before to create these reports. Gradle ecosystem is still work in progress to support multi-module Java projects [1] [2].