Knowing that tests pass is not enough — knowing what percentage of code they actually exercise is
A test suite with 100 passing tests sounds impressive. But if those tests only exercise 40% of the code, 60% of the logic has never been validated. Critical error-handling paths, edge-case branches, and security-relevant code may never have been executed.
White-box techniques use knowledge of the internal structure to design tests that maximise code coverage. Coverage metrics provide an objective measure of how thoroughly the code has been tested — not just how many tests exist.
// example: github — branch coverage revealing untested error paths
White-Box Techniques — CTFL 4.0.1
Statement Coverage
Measures the percentage of executable statements exercised by the test suite. A statement is covered if it is executed at least once during testing.
Formula: Statement Coverage (%) = (Number of statements executed ÷ Total number of executable statements) × 100
Limitation: Statement coverage does not distinguish between branches of a decision. An IF statement with no ELSE can show 100% statement coverage even if the false branch is never tested.
Branch Coverage (Decision Coverage)
Measures the percentage of branches (true/false outcomes of decision points) exercised by the test suite. Every IF, WHILE, FOR, and SWITCH creates at least two branches.
Formula: Branch Coverage (%) = (Number of branches executed ÷ Total number of branches) × 100
Branch coverage subsumes statement coverage — achieving 100% branch coverage automatically achieves 100% statement coverage. The reverse is not true.
Why coverage is not the whole story
Coverage measures which code was executed — not whether it was tested correctly. 100% statement coverage with wrong expected results is still 100% coverage. Use coverage as a guide to find untested code, not as a quality guarantee.
// tip: Exam Tip: Branch coverage subsumes statement coverage. This means 100% branch coverage guarantees 100% statement coverage — but 100% statement coverage does NOT guarantee 100% branch coverage. The exam will test this relationship. If asked which is stronger, branch coverage is always stronger than statement coverage.
Calculating Statement and Branch Coverage
Scenario: A discount function has the following logic (pseudo-code):
function calculateDiscount(isPremium, orderTotal): S1: discount = 0 S2: if isPremium == true: ← Decision 1 (Branch T/F) S3: discount = 0.10 S4: if orderTotal > 100: ← Decision 2 (Branch T/F) S5: discount = discount + 0.05 S6: return discount
| Test Case | isPremium | orderTotal | Statements Hit | Branches Hit |
|---|---|---|---|---|
| TC1 | true | 150 | S1, S2, S3, S4, S5, S6 | D1-True, D2-True |
| TC2 | false | 50 | S1, S2, S4, S6 | D1-False, D2-False |
After TC1 + TC2:
- Statements executed: S1, S2, S3, S4, S5, S6 = 6/6 → Statement coverage: 100%
- Branches executed: D1-True, D1-False, D2-True, D2-False = 4/4 → Branch coverage: 100%
If only TC1 was run: Statements = 6/6 = 100%, but Branches = D1-True, D2-True only = 2/4 = 50% branch coverage. This shows why 100% statement coverage does not guarantee 100% branch coverage.
White-Box Coverage Explorer
// Discount calculation function
■Branch covered ■Statement only □ Not covered
// Select test cases
Statement Coverage
100%
6/6 statements
Branch Coverage
100%
4/4 branches
// Key relationship
Branch coverage subsumes statement coverage. If you achieve 100% branch coverage, you automatically have 100% statement coverage. The reverse is NOT true — you can have 100% statement coverage with only 50% branch coverage (e.g., testing only TC1 above).
// Exam trap
"100% code coverage means the software has no defects" is FALSE. Coverage measures which code was executed — not whether it was tested with correct expected results. A test suite can achieve 100% branch coverage while testing with completely wrong assertions and miss every defect.
White-Box Coverage Criteria Compared
| Coverage Type | What is Measured | Strength | Subsumes |
|---|---|---|---|
| Statement coverage | % of executable statements executed | Weakest | Nothing |
| Branch coverage | % of decision outcomes (true/false) exercised | Stronger | Statement coverage |
| Path coverage | % of all execution paths through a module | Strongest | Branch and statement coverage |
Why path coverage is rarely achieved: A function with 10 decisions has 2¹⁰ = 1,024 possible paths. Testing all paths is practically impossible for any non-trivial code. Branch coverage offers the best practical trade-off between thoroughness and cost.
// warning: Exam Trap: "100% code coverage means the software has no defects." This is fundamentally false. Coverage measures which code was executed — not whether it was tested with the right expected results, not whether the logic is correct, and not whether non-functional requirements are met. A test suite can achieve 100% branch coverage while testing with completely wrong expected results and miss every defect.
Exam Practice Questions
// ctfl 4.0.1 style — select an answer to reveal explanation