skip to content

A teammate sets `ignoreFailures`, `failFast`, and `testLogging` thinking they all relate to handling failures. Explain how these three differ and how they compose.

level: seniorimportance: should knowfreq 35%

answer

  1. three orthogonal axes
  2. failFast = when execution stops
  3. ignoreFailures = build outcome
  4. testLogging = console output only
  5. can be freely combined

basics

~20 s

They answer different questions: failFast = when execution stops (first failure vs. run all); ignoreFailures = whether the build fails on test failures; testLogging = what prints to the console. They are orthogonal and can be combined.

solid answer

~40 s

These three Test-task settings are independent axes. `failFast` (default false) controls **execution termination** — stop after the first failure or run the whole suite. `ignoreFailures` (default false) controls the **build outcome** — whether failing tests make the build exit non-zero. `testLogging` controls **console observability** — which events and how much of a stack trace appear, with zero effect on outcome or scheduling. Because they're orthogonal you can mix them: e.g. local dev might use `failFast = true` + verbose `testLogging` for quick, readable feedback; a report-always module might use `ignoreFailures = true` + a downstream gate; release runs leave failFast/ignoreFailures false and crank logging to FULL. The classic mistake is expecting `testLogging` or `ignoreFailures` to change *which* tests run, or expecting `failFast` to alter the build's pass/fail decision.

code

kotlin · 7 lines
kotlin
tasks.named<Test>("test") {
    failFast = true        // when to stop
    ignoreFailures = false // build outcome
    testLogging {          // what prints
        exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
    }
}

go deeper

for a junior

Just recognize the three are different and name one effect of each.

for a middle

Cleanly separate the three axes (when-stop / build-outcome / console) and give a default for each.

for a senior

Reason about composition, edge combinations, and the right home (CLI vs. script vs. convention plugin) for each setting.

for a principal

Define org policy: convention-plugin testLogging defaults, gated ignoreFailures, failFast off shared scripts; tie to CI cost, readability, and not hiding regressions.

## Three orthogonal axes All three live on the `Test` task but answer distinct questions: | Property | Axis | Default | Effect | |---|---|---|---| | `failFast` | When does execution stop? | false | true → abort the run on the first failure | | `ignoreFailures` | Does the build fail? | false | true → build exits 0 even with failing tests | | `testLogging` | What is printed? | FAILED + SHORT | selects events + stack-trace verbosity | ## Why they're independent - `failFast` schedules/cancels test execution. It changes the *set of tests that actually ran*, but not the verdict on those that did. - `ignoreFailures` is evaluated **after** the run completes; it only decides whether to throw. It never changes scheduling or logging. - `testLogging` is a pure side-channel: it formats events as they occur. Removing all logging wouldn't change results or exit codes. ## Composition examples ```kotlin import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent // Local inner loop: stop early, show everything, still fail the build tasks.named<Test>("test") { failFast = true ignoreFailures = false testLogging { events(TestLogEvent.PASSED, TestLogEvent.FAILED, TestLogEvent.SKIPPED) exceptionFormat = TestExceptionFormat.FULL } } ``` ```kotlin // Report-always aggregation module: never fail here, gate downstream tasks.named<Test>("integrationTest") { ignoreFailures = true finalizedBy("verifyAggregatedResults") } ``` ## Edge combinations - `failFast = true` + `ignoreFailures = true`: stop at the first failure **and** keep the build green. Rare, but valid — proves the axes are separate. - Verbose `testLogging` with `ignoreFailures = true`: you'll see the failures clearly in the console even though the build passes — which is exactly why you need an external gate, since humans/CI may glance at exit code only. ## Decision guidance - Make `failFast` a per-developer CLI choice (`--fail-fast`), not a shared script default. - Treat `ignoreFailures` as a deliberate, gated exception — never a blanket setting. - Standardize `testLogging` in a convention plugin for consistent, readable CI output.

  • Which of these three would change the actual set of tests that executed in a run?
    Only `failFast`, because it aborts scheduling after the first failure so later tests never run. `ignoreFailures` and `testLogging` don't affect which tests execute.
  • If a build has verbose testLogging showing failures but exits 0, what's wrong and how do you fix it?
    `ignoreFailures` is likely true, so the build passes despite failures. Either set it back to false, or keep it and add a downstream verification task/CI step that inspects the JUnit XML and fails on errors.
  • Where should each setting ideally live?
    failFast on the CLI per developer; ignoreFailures only behind an explicit gate in specific modules; testLogging centralized in a convention plugin for consistent output.

saying these in an interview costs you the question

  • Lumping all three as 'failure handling' and assuming they overlap.
  • Believing testLogging or ignoreFailures changes which tests run.
  • Believing failFast changes the build's pass/fail verdict.

context