Engineering Method

Coverage, as a game

Every if multiplies the ways code can behave. So how many tests do you actually need? Everything below is built from one thing: a unit, a single branch of a decision. It is a row in a table, a test in the suite, and a pip on this page, all the same object. It wears one of four states, everywhere.

  • Won Verified at its level. Counts toward 1.
  • Open Owed a test. Holds the score below 1.
  • Escalated Lives above unit: architecture we do not own.
  • Parked Unreachable today. Kept, never deleted.

1 · The explosion

3 conditions
Path coverage 2ᵏ
0

Every combination. Explodes.

Branches × 2 2k
0

The tempting shortcut. Wrong past k=2.

MC/DC k + 1
0

What you actually write. Stays calm.

At k = 1 and k = 2 all three agree, which is exactly why the shortcut looks correct. Push past 2 and watch path coverage detonate while MC/DC barely moves.

2 · Find the tests

Required tests found: 0 / 3

if ( && )
    // then: happy path
else
    // else: sad path

Toggle c1 and c2 to visit every reachable row.

c1c2OutcomeRole
T T then Happy path
F T else Flip c1
T F else Flip c2
F F else Redundant

3 · Nothing is lost

A branch a unit test cannot reach does not disappear. It bubbles up to the level that can verify it, and stays documented there.

Manual Last resort. A documented human step. Still tracked.
Smoke Observed against the live deployment.
E2E Through the running app, when a unit cannot isolate it.
Unit Fast, isolated, preferred. Most branches live here.

The decisions behind it

  1. Which criterion? MC/DC, not branches×2 (breaks at 3 conditions) and not 2ᵏ path coverage (explodes).
  2. Prune unreachable rows? No. Every branch is a permanent row. A future change can make it live.
  3. A branch a unit cannot reach? It bubbles up the pyramid (E2E → smoke → manual). It is never lost.
  4. "Cannot be tested"? A finding, not an exemption: fix the missing seam, or document why we do not own it.