skip to content

How do you set up test report aggregation across several subprojects? Walk through applying the plugin and declaring what gets aggregated.

level: middleimportance: must knowfreq 50%

answer

  1. apply on aggregating/app project
  2. testReportAggregation(project(...))
  3. testSuiteName default 'test'
  4. run testAggregateTestReport
  5. aggregated-results/index.html

basics

~10 s

Apply test-report-aggregation on an aggregating project, add each subproject via the testReportAggregation dependency configuration, then run testAggregateTestReport to get one merged HTML report.

solid answer

~40 s

Pick an aggregating project — often a dedicated `:test-report` project, or the `application` project. Apply `id("test-report-aggregation")` there. The plugin creates a `testReportAggregation` configuration; declare each project you want included with `testReportAggregation(project(":foo"))`. The plugin reads the `testSuiteName` (default `test`) to know which suite's results to gather, and registers the `testAggregateTestReport` task that resolves the result-data variant from every declared project and writes a single HTML report. If you apply the `jvm-test-suite` plugin you can aggregate by suite name (e.g. an `integrationTest` suite). The merged report lands under `build/reports/tests/<suite>/aggregated-results/index.html`. Crucially, only projects that actually ran tests and exposed their result variant are included, and the aggregating project itself doesn't need to run tests.

code

kotlin · 16 lines
kotlin
plugins {
    id("test-report-aggregation")
}

dependencies {
    testReportAggregation(project(":service-a"))
    testReportAggregation(project(":service-b"))
}

reporting {
    reports {
        val testAggregateTestReport by getting(AggregateTestReport::class) {
            testSuiteName = "test"
        }
    }
}

go deeper

for a junior

Recall the three steps: apply plugin, add testReportAggregation project deps, run the task.

for a middle

Explain suite-name binding, the resolvable configuration, and that the aggregator runs no tests of its own.

for a senior

Cover hosting choices (dedicated vs app project) and aggregating multiple suites via jvm-test-suite integration.

for a principal

Standardize a convention plugin so every multi-project repo wires aggregation identically and publishes the report as a CI artifact.

## Step 1 — choose where aggregation lives Two common placements: - A **dedicated project** (e.g. `:test-report`) whose only job is to depend on others and aggregate. Keeps build logic clean. - The **application project**, which already depends on the libraries it ships, so aggregation is "free." ## Step 2 — apply the plugin ```kotlin // test-report/build.gradle.kts plugins { id("test-report-aggregation") } ``` Applying it brings in a resolvable configuration named **`testReportAggregation`** and registers the **`testAggregateTestReport`** task. ## Step 3 — declare what to include ```kotlin dependencies { testReportAggregation(project(":service-a")) testReportAggregation(project(":service-b")) testReportAggregation(project(":lib-core")) } ``` These are ordinary project dependencies on a special configuration. Gradle's variant-aware resolution then asks each target project for its **test-results** outgoing variant. ## Step 4 — configure which suite The report is bound to a *test suite name*. With the default `java`/`jvm-test-suite` `test` suite you usually get this automatically. To customize: ```kotlin reporting { reports { val testAggregateTestReport by getting(AggregateTestReport::class) { testSuiteName = "test" } } } ``` For an `integrationTest` suite defined via `jvm-test-suite`, you can register a second aggregate report against that suite name. ## Step 5 — run it ```bash ./gradlew :test-report:testAggregateTestReport ``` Output: `test-report/build/reports/tests/test/aggregated-results/index.html`. ## What gets pulled in Only projects that (a) you declared on the configuration and (b) actually produce result data for the requested suite. A project with no tests simply contributes nothing. The aggregating project need not run any tests itself. ## Relationship to jvm-test-suite The `jvm-test-suite` plugin models suites as first-class; `test-report-aggregation` keys off suite names, so the two are designed to work together — one aggregate report per suite.

  • Does the aggregating project itself need to run tests?
    No. It only needs the project dependencies; it gathers and merges results from the declared projects without running its own tests.
  • How would you aggregate an `integrationTest` suite separately from unit tests?
    Define the suite with `jvm-test-suite`, then register a second aggregate report whose `testSuiteName` matches `integrationTest`, producing a distinct merged report.
  • What configuration name do you declare dependencies on?
    `testReportAggregation` — created by the plugin.

saying these in an interview costs you the question

  • Claiming you must list file paths to each subproject's results — you declare project dependencies, not paths.
  • Forgetting that suites are matched by name and assuming one report covers every suite automatically.

context