What does the jacocoTestCoverageVerification task do in a Gradle build, and how do you make it fail the build when coverage drops below a threshold?
answer
- jacocoTestCoverageVerification = gate, not report
- violationRules { rule { limit { minimum } } }
- reads build/jacoco/test.exec
- not in check by default — wire it
- fail = non-zero exit
basics
~10 sIt's a JaCoCo plugin task that checks coverage against rules you define in violationRules. If coverage is below the configured minimum, the task fails, which fails the build.
solid answer
~40 sThe `jacocoTestCoverageVerification` task is added by the `jacoco` plugin alongside `jacocoTestReport`. You configure it with a `violationRules` block containing one or more `rule {}` entries; each rule has `limit { ... }` clauses specifying a `counter`, a `value`, and a `minimum` (or `maximum`). When you run the task, JaCoCo reads the `.exec` execution data, computes the metric, and if any rule is violated the task throws and the build fails with a non-zero exit code. By default the task is NOT part of `check`, so you typically wire it in with `check.dependsOn(jacocoTestCoverageVerification)` so CI enforces the gate. A common rule: instruction coverage minimum 0.80 across the whole bundle.
code
kotlin · 17 linesplugins { jacoco }
tasks.jacocoTestCoverageVerification {
violationRules {
rule {
limit {
counter = "INSTRUCTION"
value = "COVEREDRATIO"
minimum = "0.80".toBigDecimal()
}
}
}
}
tasks.named("check") {
dependsOn(tasks.named("jacocoTestCoverageVerification"))
}go deeper
Know it exists, that it's a separate task from the report, and that violationRules with a minimum makes the build fail.
Be able to write the violationRules block from memory and explain wiring it into check via dependsOn.
Discuss counter/value choices, why it's opt-in, and how it fits a CI quality gate.
Frame coverage gates as policy, including how to roll thresholds out org-wide without blocking teams overnight.
## What it is The `jacoco` Gradle plugin adds two main tasks: `jacocoTestReport` (generates HTML/XML/CSV reports) and `jacocoTestCoverageVerification` (a *gate* that fails the build when coverage rules are not met). This leaf is about the verification task specifically. ## Where the data comes from JaCoCo instruments your bytecode during `test` and writes execution data to a `.exec` file (default `build/jacoco/test.exec`). The verification task consumes that `.exec` plus the compiled classes to compute coverage, exactly like the report task — but instead of rendering output, it asserts thresholds. ## Configuring violationRules You configure the task's `violationRules { }` block. Each `rule { }` evaluates one or more `limit { }` clauses. A limit has three parts: - `counter` — what to count: `INSTRUCTION` (default), `LINE`, `BRANCH`, `COMPLEXITY`, `METHOD`, `CLASS`. - `value` — how to express it: `COVEREDRATIO` (default, 0.0–1.0), `TOTALCOUNT`, `COVEREDCOUNT`, `MISSEDCOUNT`, `MISSEDRATIO`. - `minimum` / `maximum` — the bound, as a `BigDecimal` (use `"0.80".toBigDecimal()` in Kotlin DSL). ## Failing the build If any active rule is violated, the task throws a `GradleException` and the build exits non-zero. That is the whole point — it turns a soft report into a hard quality gate. ## Wiring into check Crucially, `jacocoTestCoverageVerification` is **not** a dependency of `check` by default (unlike, say, `test`). So nothing enforces it unless you opt in: ```kotlin tasks.named("check") { dependsOn(tasks.named("jacocoTestCoverageVerification")) } ``` This makes `./gradlew check` (and therefore CI) run the gate. The verification task already depends on `test` transitively for its input data, so ordering is handled. ## Example ```kotlin tasks.jacocoTestCoverageVerification { violationRules { rule { limit { counter = "INSTRUCTION" value = "COVEREDRATIO" minimum = "0.80".toBigDecimal() } } } } ```
- Why isn't jacocoTestCoverageVerification run automatically by check?The plugin deliberately does not wire it into check, because coverage thresholds are a project policy decision. Teams opt in explicitly via dependsOn so they choose when the gate becomes blocking.
- Where does the coverage data the verification task reads come from?From the JaCoCo execution data file (build/jacoco/test.exec) produced when the test task runs with the JaCoCo agent attached, combined with the compiled class files.
saying these in an interview costs you the question
- Claiming check already runs the verification task automatically — it does not by default.
- Confusing jacocoTestCoverageVerification (the gate) with jacocoTestReport (the report).
- Saying it reads the HTML report — it reads the .exec execution data plus classes.