Day 10 of 60
·
Unit, integration, contract
Code coverage (with caveats)
A coverage number is signal, not target. Set a hard gate and the team writes vacuous tests; surface it in PRs and it points reviewers at the soft spots.
ProblemUntested code paths are invisible until they ship a bug.
How it works
Instruments tests to record which lines/branches executed. Surface coverage in PRs, but never set hard gates; it inverts the incentive.
What it catches
Surfaces untested areas for review. Does not catch bugs directly. Pairs with mutation testing to avoid Goodhart's trap.
Tools
Coverage.py · OSS Istanbul / nyc · OSS Codecov · Hybrid
Verdict by project size
Small
Opt
Medium
Rec
Large
Rec
Extra-large
Rec
Cost
| Project size | Setup | Maint / mo | Tool / mo | CI / run |
|---|---|---|---|---|
| Small <10k LOC | 2h | 0.5h | $0 | +0.5m |
| Medium 10–100k LOC | 4h | 2h | $0 | +1m |
| Large 100k–1M LOC | 2d | 8h | $200 | +3m |
| Extra-large >1M LOC | 5d | 25h | $1k | +8m |
Setup = engineer-days to first useful run ·
Maint = engineer-hours / month at steady state ·
Tool = out-of-pocket $ / month ·
CI = minutes added (or saved) per pipeline run
Lifecycle & ownership
When in lifecycle
Code Test
Per pull request · Runs in CI on every PR; gates merge.
Who owns it
Developer
Authoring + the inner loop
Collaborates with: QA / Test Engineer
Reference implementations
-
nyc / Istanbul
Line and branch coverage instrumentation with CI reporting patterns.
-
coverage.py
Reference Python coverage implementation with branch and report support.
-
Codecov example repository
CI coverage reporting example with pull-request feedback.
Quick check
Why are hard coverage gates considered an anti-pattern?
One question. Pick the best answer. Your streak is saved locally on this device.
Save the lesson
Download SVG ↓Screenshot for a 1:1, drop it in Slack, or download the SVG.