Branch Coverage
Exercise every branch from every decision point — both true and false. Branch coverage is stronger than statement coverage and is the standard minimum for most production code.
What it is
Branch coverage (also called decision coverage) measures whether every branch from every decision point in the code has been taken at least once. A decision point is any point where execution can split: if/else, switch, while, for, ternary operators.
For every decision, there are at least two branches: the path taken when the condition is true, and the path taken when it’s false. 100% branch coverage requires both to be tested.
Worked example
function getDiscount(user, total) {
let discount = 0;
if (user.isMember) { // Decision 1: TRUE branch / FALSE branch
discount = 0.10;
if (total > 100) { // Decision 2: TRUE branch / FALSE branch
discount = 0.15;
}
}
return discount;
}
| Test | Input | D1 branch | D2 branch |
|---|---|---|---|
| TC1 | Non-member, any total | FALSE ✓ | — (not reached) |
| TC2 | Member, total ≤ 100 | TRUE ✓ | FALSE ✓ |
| TC3 | Member, total > 100 | TRUE (already covered) | TRUE ✓ |
Three tests achieve 100% branch coverage — and in doing so, they also achieve 100% statement coverage. Branch coverage always subsumes statement coverage.
vs statement coverage
100% statement coverage is achievable with a single test (member, total = 150). That test never triggers the non-member path or the below-$100 path. Branch coverage forces you to test those paths too.
Rule of thumb: target 100% branch coverage for business logic, utility functions, and validation code. Accept lower thresholds for generated code, UI templates, and error handlers that can’t be practically triggered.
Coverage targets by context
- Safety-critical / financial code: 100% branch coverage, plus MC/DC (Modified Condition/Decision Coverage)
- Core business logic: 100% branch coverage
- Standard application code: 80%+ branch coverage is a common industry target
- Generated or boilerplate code: exclude from measurement
ISTQB mapping
| Ref | Topic |
|---|---|
| 4.3.2 | Branch Testing and Coverage |
| FL-4.3.2 K2 | Explain branch testing and branch coverage |
| FL-4.3.2 K2 | Explain the value of branch coverage over statement coverage |
Practice this technique: Try Test Lead Practice 07 — Test coverage gaps.
Try It — Design for branch coverage
A NZ loyalty rewards function has two decisions (D1, D2). Select the minimum set of test cases needed to achieve 100% branch coverage — both TRUE and FALSE branches of every decision.
function calculateReward(user, purchaseAmount) {
let points = 0;
if (user.isLoyaltyMember) { // D1
points = purchaseAmount * 2;
if (purchaseAmount >= 100) { // D2
points = points * 1.5; // bonus multiplier
}
}
return points;
}
Select the test cases to include in your branch coverage suite:
Minimum suite for 100% branch coverage
| Test case | D1 branch | D2 branch | In minimum suite? |
|---|---|---|---|
| TC1: Non-member, $200 | FALSE ✓ | — (not reached) | Yes — covers D1 FALSE |
| TC2: Member, $50 | TRUE ✓ | FALSE ✓ | Yes — covers D1 TRUE and D2 FALSE |
| TC3: Member, $150 | TRUE (already covered) | TRUE ✓ | Yes — covers D2 TRUE |
| TC4: Non-member, $0 | FALSE (already covered by TC1) | — (not reached) | No — redundant with TC1 |
| TC5: Member, $100 | TRUE (already covered) | TRUE (already covered by TC3) | No — all branches already covered |
Minimum set = TC1 + TC2 + TC3. TC4 and TC5 add no new branch coverage. 3 tests achieve 100% branch coverage for this function. TC5 at exactly $100 would be valuable as a BVA boundary test — but that's a separate concern from branch coverage.