What Is Branch Coverage?
Branch coverage measures whether every possible path through each decision point in your code was taken by your tests.
Branch coverage, sometimes called decision coverage, is a stricter cousin of line coverage. Instead of asking whether a line ran, it asks whether each true and false outcome of every if, loop, and conditional was exercised. That makes it much harder to fool with shallow tests.
Branches versus lines
A single line can contain a decision with two outcomes. Line coverage marks the line as covered if it ran at all, even if only one outcome was tested. Branch coverage requires that both the true and the false path were taken, so it catches untested else-paths that line coverage misses.
A clear example
A guard clause needs two tests to be fully branch-covered: one where the condition is true and one where it is false. A single happy-path test leaves the other branch dark.
function discount(price, isMember) {
if (isMember) return price * 0.9; // need member case
return price; // and non-member case
}Why it is a better signal
- It exposes untested else and default paths.
- It is harder to inflate with trivial tests.
- It correlates better with real defect detection.
- It highlights complex conditionals that need more tests.
Practical limits
Full branch coverage on deeply nested conditionals can require many tests, with diminishing returns. Teams often set a branch-coverage target lower than 100 percent and focus the strictest goals on critical modules rather than boilerplate.
Branch coverage in CI
Most coverage tools report branch coverage alongside line coverage, and pipelines can gate on it. Because branch instrumentation adds overhead, running the suite on fast runners keeps the stricter measurement from slowing each push.
Key takeaways
- Branch coverage requires both outcomes of each decision to be tested.
- It is stricter and more honest than line coverage.
- Aim for high branch coverage on critical code, not everywhere.