skip to content

How do you enable JaCoCo code-coverage reporting in a Gradle build, and what does applying the jacoco plugin give you?

level: juniorimportance: must knowfreq 70%

answer

  1. core plugin, apply by id
  2. no dependency needed
  3. agent attaches to Test task
  4. writes build/jacoco/test.exec
  5. registers jacocoTestReport

basics

~10 s

Add jacoco to the plugins {} block. Gradle then adds a jacocoTestReport task and a jacoco {} extension, and instruments your tests so coverage data is collected when you run test.

solid answer

~40 s

JaCoCo is enabled by applying Gradle's built-in `jacoco` plugin in the `plugins {}` block — no external dependency or version is needed because it ships with Gradle. Applying it does three things: it adds the `jacoco {}` extension (where you can set `toolVersion`), it registers a `JacocoReport` task named `jacocoTestReport` for the `test` task, and it configures the `test` task so the JVM runs with the JaCoCo agent attached, writing execution data to `build/jacoco/test.exec`. The report task is *not* part of `check` by default and does not run automatically when you run `test`; you invoke `./gradlew test jacocoTestReport` or wire a dependency. You typically also pin `toolVersion` so the agent matches your JDK bytecode level.

code

kotlin · 10 lines
kotlin
plugins {
    java
    jacoco
}

jacoco {
    toolVersion = "0.8.12"
}

// Run: ./gradlew test jacocoTestReport

go deeper

for a junior

Know that you add jacoco to the plugins block and run jacocoTestReport to get coverage.

for a middle

Explain the agent/exec-data vs report split and that the report task isn't run by test automatically.

for a senior

Discuss toolVersion pinning against JDK bytecode levels and where outputs land for CI consumption.

for a principal

Frame coverage as a build-policy concern: standardizing the plugin + version across modules via a convention plugin so every team reports consistently.

## What JaCoCo is JaCoCo ("Java Code Coverage") is a library that measures which lines, branches, and instructions of your code were exercised while tests ran. It works by **instrumenting** bytecode on the fly via a Java agent: when the test JVM starts, the agent records every executed instruction into a binary **execution-data file** (an `.exec` file). A separate **report** step reads that `.exec` file plus your compiled `.class` files and source files to produce human- and machine-readable coverage reports. ## The Gradle `jacoco` plugin Gradle ships a core plugin you apply by id — there is no Maven-style dependency to declare: ```kotlin plugins { java jacoco } ``` Applying it performs three jobs: 1. **Adds the `jacoco {}` extension** of type `JacocoPluginExtension`, where you configure the agent/tooling: most commonly `toolVersion = "0.8.12"` and optionally `reportsDirectory`. 2. **Configures every `Test` task** so the JaCoCo agent is attached. After a test run, execution data lands in `build/jacoco/<testTaskName>.exec` (e.g. `build/jacoco/test.exec`). 3. **Registers a `jacocoTestReport` task** of type `JacocoReport`, pre-wired to read the `test` task's execution data and the main source set's classes/sources. ## Pinning the tool version The JaCoCo agent must understand the bytecode your JDK produces. With newer JDKs you frequently bump `toolVersion` to a release that supports that class-file major version, otherwise instrumentation fails with an "Unsupported class file major version" error. Set it once in the extension: ```kotlin jacoco { toolVersion = "0.8.12" } ``` ## It does not run by itself A common surprise: `jacocoTestReport` is **not** a dependency of `check` and `test` does **not** trigger it. Running `./gradlew test` produces only the `.exec` data; you must also run the report task (or wire it — covered separately). The report task is also `UP-TO-DATE`/cacheable based on its inputs, so re-running without new test execution data skips work. ## Where outputs land - Execution data: `build/jacoco/test.exec` - HTML report (when enabled): `build/reports/jacoco/test/html/index.html` - XML report (when enabled): `build/reports/jacoco/test/jacocoTestReport.xml`

  • Does running `./gradlew test` produce a coverage report?
    No. The `test` run only writes execution data to `build/jacoco/test.exec`. You must also run `jacocoTestReport` (or wire it as a finalizer/dependency) to render HTML/XML.
  • Why might you need to set `toolVersion`?
    The bundled JaCoCo version may not support the class-file major version emitted by a newer JDK, causing instrumentation failures. Pinning a newer `toolVersion` fixes it.

saying these in an interview costs you the question

  • Claiming you must add a `jacoco` dependency in `dependencies {}` — it is a core plugin applied by id.
  • Assuming the report is generated automatically by the `test` task.

context