Home Multi-project test report aggregation
Post
Cancel

Multi-project test report aggregation

Context

We have a multi-project build using multiple jvm test suites (unit tests and integration tests). I want to aggregate the test reports of all these projects, irrespective of test type, into a single report. Googling the issue seemed to yield no results, other than an inconclusive thread.

I asked for advice on the Gradle community slack and got help from Björn once again (see “Accidental task avoidance” where he helped me last time) 🙂

Solution

Define outgoing variants containing all test suites

We create a new test suite type called “all”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// in `buildSrc/src/main/kotlin/uses-message-broker.gradle.kts`

/**
 * Create an outgoing variant for all test results.
 * By default, there's only variants defined per test suite type, so it's impossible
 * to aggregate unit tests with integration tests
 */
val testResultsElementsForAllTests by configurations.consumable("testResultsElementsForAllTests") {
   description = "Directory containing binary results of running tests for all test suite targets."
   isVisible = false
   attributes {
      attribute(CATEGORY_ATTRIBUTE, objects.named(VERIFICATION))
      attribute(TEST_SUITE_TYPE_ATTRIBUTE, objects.named("all"))
      attribute(VERIFICATION_TYPE_ATTRIBUTE, objects.named(TEST_RESULTS))
   }
}

And then we add the results from the tests, irrespective of test suite type, to the newly defined configuration.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
pluginManager.withPlugin("jvm-test-suite") {
   project
      .testing
      .suites
      .withType<JvmTestSuite>()
      .configureEach { // configure each suite
         targets.configureEach { // not sure what this does
            // add the binary results directory to the "all" results
            testResultsElementsForAllTests.outgoing.artifact(
               testTask.flatMap { it.binaryResultsDirectory },
            ) { 
               type = DIRECTORY_TYPE
            }
         }
      }
}

Aggregating the report

In the aggregating project we start adding the following.

1
The aggregating project can be any project in the build. In my case, I chose to put it in the root project.
1
2
3
4
plugins {
   // other plugins
   `test-report-aggregation`
}

Configure the report to use our new “all” variant.

1
2
3
4
5
reporting {
   val overallTestReport by reports.registering(AggregateTestReport::class) {
      testType.set("all")
   }
}

Add dependencies to all projects you want to include in the report. We can do this for all projects using the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
dependencies {
   rootProject.allprojects
      // All directories are included in `allprojects`, including those which only hold subprojects
      // These projects have synthetic "build.gradle" files as buildFile, so we can filter on that.
      // Perhaps there's a better way to exclude these projects...
      .filter { it.buildFile.absolutePath.endsWith(".kts") }
      .forEach {
         testReportAggregation(project(it.buildTreePath)) {
            // Don't include transitive dependencies
            setTransitive(false)
         }
      }
}
This post is licensed under CC BY 4.0 by the author.