skip to content

How do you configure `testLogging` so the console shows passed, skipped, and failed test events with full stack traces?

level: middleimportance: must knowfreq 60%

answer

  1. testLogging { } block
  2. events: passed/skipped/failed
  3. exceptionFormat = FULL
  4. default logs only FAILED + SHORT
  5. showCauses / showStackTraces

basics

~10 s

Inside the test task use a testLogging { } block: set events("passed", "skipped", "failed") to print each event, and exceptionFormat = TestExceptionFormat.FULL to show complete stack traces instead of truncated ones.

solid answer

~40 s

Gradle's `Test` task exposes a `testLogging` container (`TestLoggingContainer`). The key knobs: `events` selects which `TestLogEvent`s appear (PASSED, SKIPPED, FAILED, STANDARD_OUT, STANDARD_ERROR, STARTED); `exceptionFormat` (`TestExceptionFormat.SHORT` default or `FULL`) controls how much of a failure's stack trace prints; `showStackTraces`, `showCauses`, `showExceptions`, and `stackTraceFilters` refine the trace; `minGranularity`/`maxGranularity` choose whether you log at the test-method or suite level. By default only failed tests print, with a short exception, so CI logs often look empty for failures. Setting `events('passed','skipped','failed')` plus `exceptionFormat = FULL` gives a readable, debuggable console. You typically also configure the `lifecycle` log level (the default) or a per-level block. Note logging is purely about console output — it doesn't change pass/fail or which tests run.

code

kotlin · 10 lines
kotlin
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent

tasks.withType<Test>().configureEach {
    testLogging {
        events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
        exceptionFormat = TestExceptionFormat.FULL
        showCauses = true
    }
}

go deeper

for a junior

Know the testLogging { events(...) } block exists and that exceptionFormat = FULL gives full stack traces.

for a middle

List the common events and exception options, explain the SHORT-default surprise, and that logging is purely cosmetic/observability.

for a senior

Cover per-log-level configuration, granularity, standard-stream capture trade-offs with parallel forks, and applying config across all Test tasks with configureEach.

for a principal

Standardize a convention plugin that sets sane testLogging defaults org-wide for readable CI logs, balancing verbosity against log volume costs.

## The `testLogging` container Every `Test` task has a `testLogging` property of type `TestLoggingContainer`. It actually holds settings *per log level* (`debug`, `info`, `lifecycle`, `warn`, `quiet`, `error`), but configuring the block directly applies to the default `lifecycle` level — the one you see in a normal `./gradlew test`. ## Events `events` takes one or more `TestLogEvent` values: - `STARTED`, `PASSED`, `SKIPPED`, `FAILED` - `STANDARD_OUT`, `STANDARD_ERROR` (capture what tests print to stdout/stderr) By default the lifecycle level logs only `FAILED`. Adding `PASSED` and `SKIPPED` gives a per-test summary line. ## Exception formatting When a test fails, how much of the throwable prints is controlled by: - `exceptionFormat`: `TestExceptionFormat.SHORT` (default — a one-liner) or `FULL` (the entire stack trace). - `showExceptions` (default true), `showCauses` (print `Caused by:` chains), `showStackTraces`. - `stackTraceFilters`: e.g. `GROOVY`, `ENTRY_POINT`, `TRUNCATE` to trim noise. For real debugging you almost always want `exceptionFormat = TestExceptionFormat.FULL`. ## Granularity `minGranularity` / `maxGranularity` choose the level in the test tree (suite vs. class vs. method) at which events are emitted. `maxGranularity = -1` (default) logs at the leaf (method) level. ## Putting it together ```kotlin import org.gradle.api.tasks.testing.logging.TestExceptionFormat import org.gradle.api.tasks.testing.logging.TestLogEvent tasks.withType<Test>().configureEach { testLogging { events( TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED, ) exceptionFormat = TestExceptionFormat.FULL showCauses = true showStackTraces = true showStandardStreams = false } } ``` In Groovy DSL the events can be passed as strings: `events 'passed', 'skipped', 'failed'` and `exceptionFormat 'full'`. ## Scope reminder `testLogging` only shapes the **console output**. It has zero effect on which tests run, the build outcome (`ignoreFailures`), or early termination (`failFast`). It's purely observability.

  • Why do failing tests sometimes show almost no detail in CI by default?
    Because the default `exceptionFormat` is `SHORT` (a truncated stack trace) and only the `FAILED` event is logged. Setting `exceptionFormat = TestExceptionFormat.FULL` and optionally `showCauses`/`showStackTraces` restores the full trace.
  • How do you see what your tests print to stdout/stderr in the console?
    Add `STANDARD_OUT` and `STANDARD_ERROR` to `events`, or set `showStandardStreams = true`. Be aware this can be very noisy with parallel forks.
  • Does configuring `testLogging` for the lifecycle level also apply when running with `--info`?
    No — each log level has its own `testLogging` config. Configuring the block applies to lifecycle; `--info` uses the `info` level's settings unless you configure `testLogging.info { ... }` too.

saying these in an interview costs you the question

  • Thinking `testLogging` changes the build result or which tests run — it only affects console output.
  • Assuming full stack traces print by default; the default is SHORT.
  • Confusing the lifecycle-level config with per-level (`info`, `debug`) blocks.

context