Skip to content

Coverage Philosophy

When to Use

Use coverage as a diagnostic signal to find untested paths — not as a goal to hit. When evaluating test suite adequacy or setting team standards, focus on what coverage does not tell you as much as what it does.

Decision

Threshold Interpretation
< 60% Insufficient for most projects; high risk of undetected bugs
60–75% Acceptable for many projects (Google considers 60% adequate)
75–85% Commendable; covers critical paths and most common branches
85–90% Excellent; diminishing returns begin here for typical code
> 90% High investment; only justified for safety-critical systems

Line coverage vs. branch coverage: Line coverage measures whether a line was executed. Branch coverage measures whether each branch (if/else, switch case, ternary) was taken in both directions. Always prefer branch coverage for logic-heavy code.

Mutation testing — the most reliable quality signal: a mutation testing tool introduces small deliberate faults (mutants) into code and checks whether at least one test fails for each. High mutation score = tests genuinely verify behavior. Tools: Stryker (JS/TS), PITest (Java), Infection (PHP), mutmut (Python). Use on critical modules, not the full codebase.

Pattern

def categorize_score(score):
    if score >= 90:       # Branch: True / False
        return 'A'
    elif score >= 80:     # Branch: True / False
        return 'B'
    return 'C'

# 100% line coverage, but 50% branch coverage:
test_categorize_score(95)  # hits True branches only
test_categorize_score(75)  # hits False branches only
# Missing: score=85 (second elif True branch)

Common Mistakes

  • Wrong: Enforcing 80% coverage without enforcing test quality → Right: Teams write hollow tests; coverage passes, production breaks
  • Wrong: Treating line coverage as branch coverage → Right: Line coverage misses uncovered branches; measure branch coverage for logic-heavy code
  • Wrong: No coverage measurement at all → Right: Add coverage tooling even if you set no mandates; it reveals untested paths
  • Wrong: Gaming coverage with meaningless assertions → Right: assert True adds zero value; coverage ticks up, signal goes down
  • Wrong: Measuring coverage over generated/trivial code → Right: Exclude DTOs, getters, config classes; they inflate numbers without value

See Also