skip to content

Inside a violationRules limit, what do the counter and value properties control, and how do they change what gets enforced?

level: middleimportance: must knowfreq 50%

answer

  1. counter = metric, value = measurement
  2. INSTRUCTION/LINE/BRANCH/COMPLEXITY/METHOD/CLASS
  3. COVEREDRATIO default vs MISSEDCOUNT
  4. BRANCH ratio = strict conditional gate
  5. MISSEDCOUNT maximum 0 = zero tolerance

basics

~10 s

counter picks the metric (INSTRUCTION, LINE, BRANCH, COMPLEXITY, METHOD, CLASS). value picks how it's measured (COVEREDRATIO, MISSEDCOUNT, TOTALCOUNT, etc.). Together with minimum/maximum they define the rule.

solid answer

~40 s

Each `limit { }` describes one assertion. `counter` selects which JaCoCo metric to evaluate — `INSTRUCTION` (bytecode instructions, the default and most granular), `LINE`, `BRANCH` (decision branches — good for catching untested conditionals), `COMPLEXITY` (cyclomatic), `METHOD`, or `CLASS`. `value` selects how that counter is expressed: `COVEREDRATIO` (default, a 0.0–1.0 fraction), or absolute counts like `COVEREDCOUNT`, `MISSEDCOUNT`, `TOTALCOUNT`, and `MISSEDRATIO`. You then bound it with `minimum` or `maximum` as a BigDecimal. So `counter="BRANCH", value="COVEREDRATIO", minimum=0.7` means at least 70% of branches covered, while `counter="CLASS", value="MISSEDCOUNT", maximum=0` means no class may be entirely uncovered. Choosing BRANCH over INSTRUCTION makes the gate stricter about conditional logic.

code

kotlin · 16 lines
kotlin
tasks.jacocoTestCoverageVerification {
    violationRules {
        rule {
            limit {
                counter = "BRANCH"
                value = "COVEREDRATIO"
                minimum = "0.70".toBigDecimal()
            }
            limit {
                counter = "CLASS"
                value = "MISSEDCOUNT"
                maximum = "0".toBigDecimal()
            }
        }
    }
}

go deeper

for a junior

Name the default (INSTRUCTION/COVEREDRATIO) and that minimum is a fraction.

for a middle

Explain each counter and value and pick sensible combinations for a goal.

for a senior

Argue why BRANCH ratio or CLASS missed-count gates catch real gaps instruction ratio misses.

for a principal

Define an org standard set of counters and defend it against gaming and false confidence.

## The anatomy of a limit A `limit { }` is a single assertion with three knobs: `counter`, `value`, and a bound (`minimum` or `maximum`). The bounds are `BigDecimal`. ## counter — which metric JaCoCo tracks several counters, from finest to coarsest granularity: - `INSTRUCTION` — individual JVM bytecode instructions. Default; least affected by formatting; very granular. - `LINE` — source lines (requires debug info). Intuitive for humans. - `BRANCH` — branches of `if`/`switch`/`?:` decisions. Best signal that conditional logic is actually exercised. - `COMPLEXITY` — cyclomatic complexity covered. Roughly: number of independent paths tested. - `METHOD` — methods entered at least once. - `CLASS` — classes with at least one executed method. ## value — how to express it - `COVEREDRATIO` (default) — covered / total, a fraction 0.0–1.0. Use with `minimum`. - `MISSEDRATIO` — missed / total. Use with `maximum`. - `COVEREDCOUNT`, `MISSEDCOUNT`, `TOTALCOUNT` — absolute integers. Use `maximum = 0` on `MISSEDCOUNT` for a zero-tolerance rule. ## Putting it together The combination matters. `BRANCH/COVEREDRATIO/minimum=0.70` is a strong rule because branch coverage is hard to game — you must actually exercise both sides of conditionals. `INSTRUCTION/COVEREDRATIO` is the common default headline number. `CLASS/MISSEDCOUNT/maximum=0` forces every class to have *some* coverage, which catches whole files nobody tested. ## Example combining two limits ```kotlin rule { limit { // headline counter = "INSTRUCTION"; value = "COVEREDRATIO"; minimum = "0.80".toBigDecimal() } limit { // no fully-untested class counter = "CLASS"; value = "MISSEDCOUNT"; maximum = "0".toBigDecimal() } } ``` Both limits in one rule must pass for the rule to pass. To enforce different scopes you use separate `rule {}` blocks instead.

  • When would you prefer BRANCH coverage over INSTRUCTION coverage in a rule?
    When you care that conditional logic is actually exercised. High instruction coverage can still leave the false side of an if untested; BRANCH coverage forces both outcomes, so it's a stronger gate for decision-heavy code.
  • How do you express a rule like 'no class may be completely untested'?
    counter = CLASS, value = MISSEDCOUNT, maximum = 0. A class with zero executed methods counts as missed, so any fully-untested class makes the count exceed 0 and fails the rule.

saying these in an interview costs you the question

  • Saying COVEREDRATIO takes a percentage like 80 instead of a fraction 0.80.
  • Thinking value and counter are interchangeable terms.
  • Believing high INSTRUCTION coverage guarantees all branches are tested.

context