skip to content

How do you configure the test reports on a `Test` task — for example disable the HTML report on CI, keep the JUnit-XML, and move the XML to a custom directory?

level: middleimportance: must knowfreq 55%

answer

  1. reports { html / junitXml }
  2. required = Property<Boolean>
  3. outputLocation = DirectoryProperty
  4. layout.buildDirectory not $buildDir
  5. mergeReruns / outputPerTestCase
  6. withType<Test>().configureEach

basics

~10 s

Use the reports {} block on the test task: set html.required = false, junitXml.required = true, and point junitXml.outputLocation at the directory you want.

solid answer

~40 s

Each `Test` task exposes a `reports` container with `html` and `junitXml` sub-reports. In modern Gradle (8.x) you toggle each with the lazy `required` property and relocate it with `outputLocation`: ```kotlin tasks.test { reports { html.required = false junitXml.required = true junitXml.outputLocation = layout.buildDirectory.dir("my-results") } } ``` Disabling HTML saves time on CI where nobody opens it, while keeping JUnit-XML for the CI parser. `required` is a `Property<Boolean>` and `outputLocation` is a `DirectoryProperty`, so both are lazy/Provider-based — that's why you assign with `=` (Gradle 8 supports the property-assignment syntax). On older Groovy builds you'd see `html.enabled` and `html.destination`, which are deprecated aliases for `required`/`outputLocation`.

code

kotlin · 9 lines
kotlin
tasks.test {
  reports {
    html.required = false
    junitXml.required = true
    junitXml.outputLocation = layout.buildDirectory.dir("my-results")
    junitXml.outputPerTestCase = true
    junitXml.mergeReruns = true
  }
}

go deeper

for a junior

Know there's a reports {} block and you can turn html/junitXml on or off.

for a middle

Configure required + outputLocation, know they're lazy properties, name the deprecated aliases.

for a senior

Apply policy across all test tasks via withType<Test>().configureEach, use mergeReruns/outputPerTestCase appropriately.

for a principal

Standardize report config in a convention plugin so every module emits CI-consumable XML uniformly.

## The reports container A `Test` task implements `Reporting<TestTaskReports>`, exposing `reports {}` with exactly two sub-reports: - `reports.html` — a `DirectoryReport` rendering the browsable site. - `reports.junitXml` — a `JUnitXmlReport` writing `TEST-*.xml`. Each has two key knobs: - **`required`** — a `Property<Boolean>` (lazy). `true` generates that report, `false` skips it. This replaced the older `enabled` flag. - **`outputLocation`** — `html` uses a `DirectoryProperty`; `junitXml` also uses a `DirectoryProperty`. Setting it relocates where that report is written, overriding the `build/reports/tests/<task>` / `build/test-results/<task>` defaults. ## Lazy properties — why `=` works These are Gradle **lazy properties** (`Property`/`DirectoryProperty`), part of the Provider API. You should source paths from `layout.buildDirectory` rather than hardcoding `"$buildDir/..."` (the latter is deprecated). Kotlin DSL in Gradle 8 supports direct property assignment (`html.required = false`); the explicit form is `html.required.set(false)`. ## JUnitXmlReport extras `junitXml` carries a couple of useful options: - `outputPerTestCase` — when `true`, captures stdout/stderr per test case into the XML (heavier but richer for CI drill-down). - `mergeReruns` — groups retried executions of the same test into a single `<testcase>` with `<rerunFailure>`/`<flakyFailure>` entries, which CI tools use to surface flaky tests instead of double-counting. ## Typical CI shape ```kotlin tasks.withType<Test>().configureEach { reports { html.required = false // nobody browses HTML on CI junitXml.required = true // CI parses this junitXml.mergeReruns = true // collapse retries into flaky markers } } ``` Using `withType<Test>().configureEach { }` applies the policy to *every* test task (including custom `integrationTest`) lazily, so newly registered tasks pick it up too. ## Legacy aliases Groovy builds and old docs use `html.enabled` / `html.destination`. These are deprecated aliases for `required` / `outputLocation`; prefer the new names.

  • What's the modern replacement for the deprecated `html.enabled` and `html.destination`?
    `html.required` (a `Property<Boolean>`) and `html.outputLocation` (a `DirectoryProperty`). The old names are deprecated aliases.
  • Why prefer `layout.buildDirectory.dir(...)` over `"$buildDir/..."`?
    `buildDir`/`$buildDir` string interpolation is deprecated; `layout.buildDirectory` is the lazy `DirectoryProperty` that plays correctly with configuration cache and Provider wiring.
  • What does `junitXml.mergeReruns = true` do?
    It collapses retried executions of the same test into one `<testcase>` with `<rerunFailure>`/`<flakyFailure>` children, so CI can flag flakiness instead of double-counting.

saying these in an interview costs you the question

  • Using `enabled`/`destination` as the current API without noting they're deprecated aliases
  • Hardcoding `$buildDir` paths instead of `layout.buildDirectory`
  • Thinking disabling HTML also disables the XML — they're independent

context