How would you architect cross-project reporting so that unit and integration test suites each get their own aggregated report, and how does this relate to coverage aggregation?
answer
- jvm-test-suite = first-class suites
- one AggregateTestReport per suite name
- jacoco-report-aggregation = coverage twin
- convention plugin to standardize
- all variant/attribute driven
basics
~10 sModel each suite with jvm-test-suite, then register one AggregateTestReport per suite name (e.g. test and integrationTest). For coverage, apply the sibling jacoco-report-aggregation plugin, which works the same way for JaCoCo data.
solid answer
~40 sUse `jvm-test-suite` so each suite (`test`, `integrationTest`, etc.) is a first-class entity with its own result variant. Because `test-report-aggregation` keys aggregation off `testSuiteName`, you register a separate `AggregateTestReport` per suite — one combined unit-test report and one combined integration-test report — giving teams clean, separated dashboards. For coverage, the parallel **`jacoco-report-aggregation`** plugin uses the identical variant-aware model to merge JaCoCo execution data from many projects into one coverage report, also keyed by suite. Put all this in a **convention plugin** so every repo wires the same aggregating project, suite names, and CI artifact paths. The result is a standardized, cache-friendly reporting layer: declare project dependencies once, get per-suite test reports plus a unified coverage report, all resolved through attributes rather than brittle paths.
code
kotlin · 10 linesreporting {
reports {
val testAggregateTestReport by getting(AggregateTestReport::class) {
testSuiteName = "test"
}
val integrationTestAggregateTestReport by creating(AggregateTestReport::class) {
testSuiteName = "integrationTest"
}
}
}go deeper
Out of scope; just know multiple suites can each have their own report.
Recall that you register one AggregateTestReport per suite name and that JaCoCo has a parallel aggregation plugin.
Wire per-suite aggregation with jvm-test-suite and pair it with jacoco-report-aggregation.
Codify the whole reporting layer in a convention plugin as the single governance point, ensuring uniform suites, reports, and CI artifacts across the org.
## First-class suites with jvm-test-suite The **`jvm-test-suite`** plugin models test suites declaratively. The built-in `test` suite is unit tests; you add others: ```kotlin testing { suites { val test by getting(JvmTestSuite::class) val integrationTest by registering(JvmTestSuite::class) { useJUnitJupiter() dependencies { implementation(project()) } } } } ``` Each suite produces its **own** result data exposed via its **own** outgoing variant, tagged with the suite name. ## One aggregate report per suite Because `test-report-aggregation` binds a report to a `testSuiteName`, you register one aggregate per suite on the aggregating project: ```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" } val integrationTestAggregateTestReport by creating(AggregateTestReport::class) { testSuiteName = "integrationTest" } } } ``` Now `testAggregateTestReport` merges unit results and `integrationTestAggregateTestReport` merges integration results — two clean, separate dashboards. ## Coverage: the sibling plugin **`jacoco-report-aggregation`** is the coverage twin. It applies the same attribute-driven resolution to collect JaCoCo `.exec` execution data across projects and render one combined coverage report, again keyed by suite via a `JacocoCoverageReport`. You declare `jacocoAggregation(project(...))` dependencies analogously. ## Standardize with a convention plugin Duplicating this wiring across dozens of repos invites drift. Extract a **convention plugin** (in `buildSrc` or an included build) that: - Applies `jvm-test-suite`, `test-report-aggregation`, and `jacoco-report-aggregation`. - Defines the standard suite names. - Registers the per-suite aggregate reports. - Documents the canonical artifact paths for CI. Teams then opt in by applying one plugin id, and every repo reports identically. ## Why this architecture - **Separation**: unit vs integration dashboards never blur together. - **Uniformity**: one coverage report, one report per suite, everywhere. - **Cache/correctness**: all inputs flow through variant resolution, so build cache and up-to-date checks apply. - **Governance**: the convention plugin is the single control point for reporting policy.
- What plugin gives you the coverage equivalent of test-report-aggregation?`jacoco-report-aggregation`, which merges JaCoCo execution data across projects into one coverage report using the same variant-aware resolution and suite keying.
- Why register a separate AggregateTestReport per suite instead of one for everything?Reports are bound to a `testSuiteName`, and separating unit from integration gives cleaner, independently-interpretable dashboards; one report can't mix suites meaningfully.
- How do you stop this wiring from drifting across many repos?Encapsulate it in a convention plugin (buildSrc or included build) so every repo applies one id and inherits identical suites, reports, and artifact paths.
saying these in an interview costs you the question
- Thinking a single aggregate report can cleanly merge unrelated suites like unit and integration tests.
- Believing coverage aggregation needs a totally different mechanism — it's the same variant model via jacoco-report-aggregation.
- Hand-duplicating aggregation config in every project instead of a convention plugin.