How does the 'element' scope in a JaCoCo violation rule work, and how would you enforce a per-class minimum while excluding generated code?
answer
- element = BUNDLE/PACKAGE/CLASS/SOURCEFILE/METHOD
- CLASS element = per-class enforcement
- excludes = FQN globs, not regex
- layer BUNDLE headline + CLASS floor
- rule excludes ≠ classDirectories excludes
basics
~10 sA rule's element sets the granularity it's applied at: BUNDLE (whole project, default), PACKAGE, CLASS, METHOD, or SOURCEFILE. Use element = CLASS to enforce per-class, and excludes to drop generated classes.
solid answer
~40 sEach `rule { }` has an `element` that controls the scope the `limit`s are evaluated against. Default is `BUNDLE` — the whole aggregated project, so one global number. Setting `element = "CLASS"` makes the rule evaluate *every class independently*: each class must individually meet the limit, and the build fails listing each violator. Other elements are `PACKAGE`, `METHOD`, and `SOURCEFILE`. With finer elements you almost always need `excludes` — a list of fully-qualified name patterns (e.g. `"*.generated.*"`, `"*MapperImpl"`) — because generated, DTO, or config classes would otherwise fail an unrealistic per-class bar. So a typical strict gate is `element="CLASS", excludes=[...], limit { minimum=0.6 }` combined with a softer `BUNDLE` headline rule.
code
kotlin · 13 linestasks.jacocoTestCoverageVerification {
violationRules {
rule { // headline
element = "BUNDLE"
limit { minimum = "0.80".toBigDecimal() }
}
rule { // per-class floor
element = "CLASS"
excludes = listOf("*.dto.*", "*Application", "*MapperImpl")
limit { minimum = "0.50".toBigDecimal() }
}
}
}go deeper
Know the default element is BUNDLE and that CLASS exists for per-class checks.
Configure element=CLASS with excludes and explain glob (not regex) semantics.
Design a layered BUNDLE + CLASS gate and justify the excludes list.
Standardize an excludes policy across modules and decide rule excludes vs computation excludes for accurate org metrics.
## What element controls A single `rule { }` is evaluated against a *set of coverage elements*. The `element` property picks the granularity: - `BUNDLE` (default) — the entire project/module as one unit. One pass/fail number. - `PACKAGE` — each package independently. - `CLASS` — each class independently. - `SOURCEFILE` — each source file independently. - `METHOD` — each method independently (rarely used; very noisy). The finer the element, the more separate checks the rule performs. With `element = "CLASS"`, a rule with `minimum = 0.6` means *every class* must hit 60%, and the failure report enumerates each class below the bar. ## Why excludes matter at fine granularity A per-class rule is brittle without filtering. Generated mappers, `@Data`/Lombok-style classes, DTOs, `*Application` bootstrap classes, and enums often have trivially-untestable or auto-generated code. JaCoCo rules support `excludes` (and `includes`) lists of FQN glob patterns evaluated against the element name: ```kotlin rule { element = "CLASS" excludes = listOf( "*.generated.*", "*MapperImpl", "*Application", "*.dto.*" ) limit { counter = "INSTRUCTION" value = "COVEREDRATIO" minimum = "0.60".toBigDecimal() } } ``` Note: rule-level `excludes` filter which *elements* the rule applies to. This is different from `classDirectories` / `afterEvaluate { ... exclude(...) }` filtering, which removes classes from the coverage computation entirely. Rule excludes are the targeted way to relax a single gate without distorting the headline number. ## Pattern: layered rules A mature setup uses two rules in one `violationRules` block: a lenient `BUNDLE` headline (e.g. 80% instructions) plus a per-`CLASS` floor (e.g. 50%) with excludes, so a single hot, untested class can't hide behind a high average. ## Gotcha Element patterns use `.`-qualified names with `*`/`?` globs, not regex. `excludes = listOf("com.acme.gen.*")` matches that package's classes.
- What's the difference between rule-level excludes and excluding classes from classDirectories?Rule excludes only stop a specific rule from applying to those elements — the classes still appear in reports and other rules/the headline number. classDirectories excludes remove the classes from coverage computation entirely, changing every number.
- Why combine a BUNDLE rule with a per-CLASS rule?The BUNDLE average can stay high while one critical class is 0% covered. A per-CLASS floor catches that hidden gap, so neither a good average nor a single rotten class slips through.
saying these in an interview costs you the question
- Treating excludes patterns as regular expressions instead of Ant-style globs.
- Putting a strict per-CLASS minimum without any excludes, then fighting generated-class failures.
- Assuming element defaults to CLASS — it defaults to BUNDLE.