White-Box Test Techniques
Black-box testing looks at the software from the outside, like a user. White-box testing looks at it from the inside - the source code and control flow - to design tests and measure exactly how much of that code your tests actually exercise.
~10 min read
The core ideas, explained
Statement Testing and Coverage
White-box techniques (also called structure-based or glass-box techniques) look at the software from the inside - specifically the source code and control flow - rather than treating it as a black box. Statement testing aims to execute every executable statement in the source code at least once - an "executable statement" being any action the code performs, like assigning a variable or printing a result. Coverage is calculated as the number of executed statements divided by the total number of executable statements, times 100.
1. Read Customer_Name
2. Read Account_Balance
3. Print Customer_Name + " has " + Account_Balance
There are no decisions here - the code just flows top to bottom. Just one test case (Input: "Alice", "$50") executes lines 1, 2, and 3 - 100% statement coverage from a single test.
1. Read Age
2. If Age >= 18 then:
3. Print "Eligible to vote"
With Age = 15, line 1 and line 2 evaluate but line 3 is skipped, giving 66% statement coverage (2/3). A single test case with Age = 20 instead executes all three lines - 100% statement coverage from just one test.
Branch Testing and Coverage
Code isn't a straight line - it branches based on decisions like If/Else, Switch cases, and loops. A branch is an edge in the control flow graph, and every decision has at least two of them: True and False. Branch coverage is the number of executed branches divided by the total number of branches, times 100. The golden rule of subsumption: 100% Branch Coverage always guarantees 100% Statement Coverage, but 100% Statement Coverage does not guarantee 100% Branch Coverage.
1. Read Age
2. If Age >= 18 then:
3. Print "Eligible to vote"
The statement-testing example above hit 100% statement coverage with just Age = 20, but that only covers the True branch - 50% branch coverage. Reaching 100% branch coverage needs 2 test cases: Age = 20 (covers True) and Age = 15 (covers False).
1. Read Order_Total
2. If Order_Total > 100:
3. Discount = 20
4. Else:
5. Discount = 0
Here, statement and branch coverage require the same tests - you can't hit line 3 and line 5 in the same test. Test 1: Order_Total = 150 (hits the True branch, executes lines 1, 2, 3). Test 2: Order_Total = 50 (hits the False branch, executes lines 1, 2, 4, 5).
The Value of White-Box Testing
Why bother looking at the code if black-box testing already checks the requirements? Because code often contains things the requirements never mention. White-box coverage tools flag unreachable dead code - an If statement that can mathematically never be true - as a statement with 0% coverage, something black-box testing would never stumble onto. They also expose unintended logic, like a hidden debugging backdoor a black-box tester following requirements alone would never trigger. Beyond finding specific defects, coverage gives an objective, mathematical metric for how thorough a test suite actually is - if your black-box tests only reach 60% statement coverage, you know you have real gaps. And it's a Shift-Left enabler, since developers can write and run white-box unit tests on an isolated function long before the UI or a real database exists.
A developer leaves in `If Username == "AdminTest" bypass password`. No requirement mentions this, so black-box testing never finds it - but a white-box coverage tool immediately flags that branch as never executed during normal testing.
Key points to remember
- Test basis = code - the source code, architecture, or control flow graph dictates the tests.
- Statement coverage = nodes - did we light up every line of code?
- Branch coverage = edges - did we take every path at every fork in the road?
- Subsumption rule: branch coverage is stronger than statement coverage - 100% branch always means 100% statement.
- Developer territory - white-box techniques are primarily used at the Component (Unit) testing level.
Terminology
A few terms from this topic worth knowing precisely.
Designing tests based on a system's internal structure or code, which requires knowledge of how the software is actually built.
A white-box metric measuring the percentage of executable statements in the source code that have been run by a test suite at least once.
A white-box metric measuring the percentage of branches - the True and False outcomes of every decision - that have been executed by a test suite.
The rule that 100% Branch Coverage always guarantees 100% Statement Coverage, because every statement sits on some branch - but the reverse is not true.
Code that can never be executed given the program's structure - notoriously hard to find by running the software, but often obvious during a static review.
Summary
White-box testing measures how much of the internal structure of the software is exercised by tests. Statement coverage ensures every executable line runs, while Branch coverage ensures every True/False decision path is taken. Because Branch testing forces the execution of all code blocks, achieving 100% Branch coverage automatically achieves 100% Statement coverage. White-box testing is invaluable for finding dead code, unintended logic, and objectively measuring test suite thoroughness.
| Concept | One-line memory hook |
|---|---|
| White-box testing | Testing with full visibility into the source code |
| Statement coverage | (Executed lines / Total lines) × 100 |
| Branch coverage | (Executed True & False paths / Total paths) × 100 |
| Subsumption | 100% Branch Coverage always guarantees 100% Statement Coverage |
| Dead code | Code that can never be executed; easily found by coverage tools |
Check your understanding
20 questions, easy to hard - click an option to see if you got it right.