
CTAL-TTA White-Box Test Techniques: Complete Coverage Analysis Guide
White-box testing techniques form the foundation of technical test analysis. Unlike black-box testing that treats the system as opaque, white-box testing uses knowledge of the internal code structure to design tests that exercise specific paths, branches, and conditions. Mastering these techniques is essential for the CTAL-TTA certification and for roles requiring code-level quality assurance.
This guide provides deep coverage of each white-box technique with practical examples, calculations, and exam-focused insights.
Table Of Contents-
- White-Box Testing Fundamentals
- Statement Coverage (C0)
- Branch Coverage (C1) / Decision Coverage
- Condition Coverage
- Condition/Decision Coverage
- Modified Condition/Decision Coverage (MC/DC)
- Multiple Condition Coverage
- Data Flow Testing
- Coverage Hierarchy and Selection
- Practical Application and Tool Integration
White-Box Testing Fundamentals
What is White-Box Testing?
White-box testing (also called structural testing, glass-box testing, or clear-box testing) designs test cases based on the internal structure of the code:
| Aspect | Description |
|---|---|
| Basis | Source code, control flow, data flow |
| Visibility | Full access to internal implementation |
| Goal | Exercise code structures systematically |
| Measurement | Coverage metrics (statement, branch, etc.) |
Control Flow Graphs
Control flow graphs (CFGs) visually represent code execution paths:
Basic Elements:
- Nodes: Represent statements or blocks
- Edges: Represent flow of control
- Decision nodes: Points where flow splits (if, while, for)
- Junction nodes: Points where paths merge
Example Code:
def validate_age(age): # Node 1: Entry
if age < 0: # Node 2: Decision
return "Invalid" # Node 3
elif age < 18: # Node 4: Decision
return "Minor" # Node 5
else:
return "Adult" # Node 6
# Node 7: ExitControl Flow Graph:
[1: Entry]
|
[2: age < 0?]
/ \
Yes No
| |
[3] [4: age < 18?]
| / \
| Yes No
| | |
| [5] [6]
\ | /
\ | /
\ | /
[7: Exit]Coverage Levels Overview
Coverage criteria form a hierarchy from weakest to strongest:
| Level | Name | Description | Subsumes |
|---|---|---|---|
| C0 | Statement | Every statement executed | - |
| C1 | Branch/Decision | Every branch taken | C0 |
| C2 | Condition | Every condition outcome | - |
| C3 | Condition/Decision | C1 + C2 combined | C1, C2 |
| MC/DC | Modified Condition/Decision | Independence shown | C3 |
| MCC | Multiple Condition | All combinations | MC/DC |
Subsumption: When criterion A "subsumes" criterion B, achieving 100% A automatically achieves 100% B. For example, 100% branch coverage guarantees 100% statement coverage.
Statement Coverage (C0)
Definition and Formula
Statement Coverage: The percentage of executable statements exercised by the test suite.
Formula:
Statement Coverage = (Executed Statements / Total Executable Statements) × 100%Detailed Example
def calculate_shipping(weight, is_express, is_member):
base_cost = 5.00 # S1
if weight > 10: # S2 (decision)
base_cost = base_cost + (weight * 0.5) # S3
if is_express: # S4 (decision)
base_cost = base_cost * 2 # S5
if is_member: # S6 (decision)
base_cost = base_cost * 0.9 # S7
return base_cost # S8Statement Count: 8 executable statements (S1-S8)
Test for 100% Statement Coverage:
| Test | weight | is_express | is_member | Statements Executed |
|---|---|---|---|---|
| T1 | 15 | True | True | S1, S2, S3, S4, S5, S6, S7, S8 |
Result: One test achieves 100% statement coverage (8/8 = 100%)
Limitations of Statement Coverage
⚠️
Critical Limitation: Statement coverage does not guarantee all branches are tested.
In the shipping example, Test T1 only tests when ALL conditions are true. We never verify the code behaves correctly when:
- weight is 10 or less
- is_express is False
- is_member is False
Bugs in the "else" paths would go undetected.
Real-World Bug Example:
def get_discount(customer_type):
discount = 0
if customer_type == "premium":
discount = 20
# Bug: missing else for "standard" customer
return discountA single test with customer_type = "premium" achieves 100% statement coverage but misses the bug where standard customers get no discount handling.
Branch Coverage (C1) / Decision Coverage
Definition and Formula
Branch Coverage: The percentage of branches (decision outcomes) exercised by the test suite.
Formula:
Branch Coverage = (Executed Branches / Total Branches) × 100%Each decision point (if, while, for, switch) has multiple branches:
- if statement: 2 branches (true, false)
- if-else: 2 branches
- switch: N branches (one per case + default)
Detailed Example
Using the same shipping function:
def calculate_shipping(weight, is_express, is_member):
base_cost = 5.00
if weight > 10: # Decision D1: 2 branches
base_cost = base_cost + (weight * 0.5)
if is_express: # Decision D2: 2 branches
base_cost = base_cost * 2
if is_member: # Decision D3: 2 branches
base_cost = base_cost * 0.9
return base_costTotal Branches: 6 (2 per decision × 3 decisions)
Tests for 100% Branch Coverage:
| Test | weight | is_express | is_member | D1 | D2 | D3 |
|---|---|---|---|---|---|---|
| T1 | 15 | True | True | True | True | True |
| T2 | 5 | False | False | False | False | False |
Branch Coverage Calculation:
- T1 executes: D1-True, D2-True, D3-True (3 branches)
- T2 executes: D1-False, D2-False, D3-False (3 branches)
- Total: 6/6 = 100% branch coverage
Branch vs Statement Coverage Relationship
Key Principle: 100% branch coverage implies 100% statement coverage.
Proof by example:
if condition:
statement_A # Only executed when branch is True
else:
statement_B # Only executed when branch is FalseTo achieve 100% branch coverage, both True and False branches must execute, which means both statement_A and statement_B must execute.
Exam Point: The reverse is NOT true. 100% statement coverage does NOT guarantee 100% branch coverage. You can execute all statements by only taking the True branches.
Loop Coverage Considerations
For loops, branch coverage requires:
- Entering the loop (True branch)
- Skipping/exiting the loop (False branch)
while items_remaining > 0: # Decision
process_item() # Loop bodyBranch Coverage Requirement:
- Test 1:
items_remaining = 5(enters loop) - Test 2:
items_remaining = 0(skips loop)
Condition Coverage
Definition and Formula
Condition Coverage: Each atomic condition within a decision evaluates to both True and False.
Formula:
Condition Coverage = (Condition Outcomes Tested / Total Condition Outcomes) × 100%Atomic Conditions vs Decisions
Decision: The overall boolean expression controlling flow Atomic Condition: Individual boolean sub-expressions connected by AND/OR
if (temperature > 100) and (pressure < 50):
# Condition 1 Condition 2
# |_____________Decision____________|
emergency_shutdown()Total Condition Outcomes: 4 (2 conditions × 2 outcomes each)
Detailed Example
def requires_review(amount, is_new_customer):
if (amount > 1000) or (is_new_customer):
# Condition A Condition B
return True
return FalseTests for 100% Condition Coverage:
| Test | amount | is_new_customer | A (amount > 1000) | B (is_new_customer) |
|---|---|---|---|---|
| T1 | 1500 | False | True | False |
| T2 | 500 | True | False | True |
Both conditions have been True and False. 100% condition coverage achieved.
Critical Limitation: Decision Outcomes
⚠️
Exam Alert: 100% condition coverage does NOT guarantee 100% branch coverage!
In the example above:
- T1: A=True, B=False → Decision = True (True OR False = True)
- T2: A=False, B=True → Decision = True (False OR True = True)
Both tests result in True decision. The False branch is never tested!
This is why condition/decision coverage exists.
Condition/Decision Coverage
Definition
Condition/Decision Coverage: Achieves BOTH 100% condition coverage AND 100% decision (branch) coverage.
Example with Proper Test Design
def requires_review(amount, is_new_customer):
if (amount > 1000) or (is_new_customer):
return True
return FalseTests for 100% Condition/Decision Coverage:
| Test | amount | is_new_customer | A | B | Decision |
|---|---|---|---|---|---|
| T1 | 1500 | False | True | False | True |
| T2 | 500 | True | False | True | True |
| T3 | 500 | False | False | False | False |
Verification:
- Condition A: True (T1), False (T2, T3) ✓
- Condition B: True (T2), False (T1, T3) ✓
- Decision: True (T1, T2), False (T3) ✓
100% Condition/Decision Coverage achieved with 3 tests.
Modified Condition/Decision Coverage (MC/DC)
Definition and Requirements
MC/DC is the most rigorous practical coverage criterion. It requires:
- Every entry and exit point is invoked
- Every decision takes all possible outcomes
- Every condition takes all possible outcomes
- Each condition independently affects the decision outcome
The fourth requirement is the key differentiator.
Independence Requirement Explained
For each condition, you must show that changing ONLY that condition (while holding others constant) changes the decision outcome.
MC/DC Example: Two Conditions
if (A and B):
action()Truth Table:
| Test | A | B | A and B |
|---|---|---|---|
| 1 | T | T | T |
| 2 | T | F | F |
| 3 | F | T | F |
| 4 | F | F | F |
Independence Pairs:
For A (B held constant):
- Compare tests where only A differs, B same
- Tests 1 and 3: A=T→F, B=T, Decision T→F ✓
For B (A held constant):
- Compare tests where only B differs, A same
- Tests 1 and 2: B=T→F, A=T, Decision T→F ✓
Minimum MC/DC Test Set: Tests 1, 2, 3 (3 tests for 2 conditions)
MC/DC Example: Three Conditions
if (A or B) and C:
critical_operation()Full Truth Table (8 combinations):
| # | A | B | C | (A or B) | (A or B) and C |
|---|---|---|---|---|---|
| 1 | T | T | T | T | T |
| 2 | T | T | F | T | F |
| 3 | T | F | T | T | T |
| 4 | T | F | F | T | F |
| 5 | F | T | T | T | T |
| 6 | F | T | F | T | F |
| 7 | F | F | T | F | F |
| 8 | F | F | F | F | F |
Finding Independence Pairs:
| Condition | Independence Pair | Effect |
|---|---|---|
| A | Tests 3 & 7 | A: T→F, B=F, C=T, Decision: T→F |
| B | Tests 5 & 7 | B: T→F, A=F, C=T, Decision: T→F |
| C | Tests 3 & 4 | C: T→F, A=T, B=F, Decision: T→F |
Minimum MC/DC Test Set: Tests 3, 4, 5, 7 (4 tests for 3 conditions = N+1)
MC/DC Formula: For N conditions, MC/DC typically requires N+1 test cases. This is dramatically fewer than the 2^N required for multiple condition coverage, making MC/DC practical for complex decisions.
MC/DC in Industry Standards
MC/DC is mandated for safety-critical software:
| Standard | Industry | MC/DC Requirement |
|---|---|---|
| DO-178C Level A | Aviation | Required |
| ISO 26262 ASIL D | Automotive | Required |
| IEC 62304 Class C | Medical Devices | Recommended |
| EN 50128 SIL 4 | Railway | Required |
Multiple Condition Coverage
Definition
Multiple Condition Coverage (MCC): Tests all possible combinations of condition outcomes within each decision.
Formula
For a decision with N conditions:
Required Tests = 2^NExample
if (A and B and C):
action()Required Tests: 2^3 = 8 test cases
| Test | A | B | C | Decision |
|---|---|---|---|---|
| 1 | T | T | T | T |
| 2 | T | T | F | F |
| 3 | T | F | T | F |
| 4 | T | F | F | F |
| 5 | F | T | T | F |
| 6 | F | T | F | F |
| 7 | F | F | T | F |
| 8 | F | F | F | F |
Practical Limitations
Exponential Growth Problem:
| Conditions | MCC Tests | MC/DC Tests |
|---|---|---|
| 2 | 4 | 3 |
| 3 | 8 | 4 |
| 4 | 16 | 5 |
| 5 | 32 | 6 |
| 10 | 1,024 | 11 |
MCC becomes impractical for decisions with many conditions, which is why MC/DC is preferred in industry.
Data Flow Testing
Fundamentals
Data flow testing focuses on the lifecycle of variables:
| Term | Definition | Example |
|---|---|---|
| Definition (def) | Variable assigned a value | x = 5 |
| Use (use) | Variable value is read | y = x + 1 |
| C-use | Computational use in calculation | result = x * 2 |
| P-use | Predicate use in condition | if x > 0: |
| Kill | Variable undefined/out of scope | End of function |
Definition-Use Pairs (du-pairs)
A du-pair connects a variable definition to a subsequent use:
def process_order(quantity, unit_price):
total = quantity * unit_price # def(total) at line 2
if total > 100: # p-use(total) at line 3
discount = 0.1 # def(discount)
total = total * (1-discount) # c-use(total), def(total) at line 5
tax = total * 0.08 # c-use(total) at line 6
return total + tax # c-use(total) at line 7Du-pairs for total:
| Definition | Use | Type |
|---|---|---|
| Line 2 | Line 3 | p-use |
| Line 2 | Line 5 | c-use |
| Line 2 | Line 6 | c-use (if condition false) |
| Line 5 | Line 6 | c-use (if condition true) |
| Line 2 | Line 7 | c-use (if condition false) |
| Line 5 | Line 7 | c-use (if condition true) |
Data Flow Coverage Criteria
From weakest to strongest:
| Criterion | Requirement |
|---|---|
| All-defs | Each definition reaches at least one use |
| All-uses | Each definition reaches all possible uses |
| All-du-paths | Every path from definition to use is tested |
Data Flow Anomalies
Data flow analysis detects anomalies:
| Anomaly | Pattern | Problem |
|---|---|---|
| ur | use before definition | Using uninitialized variable |
| dd | definition followed by definition | First definition wasted |
| du | definition followed by kill | Defined but never used |
Example Detecting Anomaly:
def buggy_function(flag):
if flag:
result = calculate() # def(result)
print(result) # use(result) - ur anomaly if flag=False!Coverage Hierarchy and Selection
Subsumption Relationships
Multiple Condition Coverage
|
\|/
Modified Condition/Decision Coverage
|
\|/
Condition/Decision Coverage
/ \
/ \
Branch Coverage Condition Coverage
|
\|/
Statement CoverageChoosing the Right Coverage Level
| Scenario | Recommended Coverage | Rationale |
|---|---|---|
| Safety-critical systems | MC/DC | Regulatory requirement, high rigor |
| Financial transactions | Branch + Condition | Balance of rigor and practicality |
| Standard business logic | Branch coverage | Good defect detection |
| Legacy code maintenance | Statement coverage | Baseline assurance |
| Quick smoke testing | Statement coverage | Rapid feedback |
Coverage Goals by Industry
| Industry | Typical Target | Standard |
|---|---|---|
| Aviation | 100% MC/DC | DO-178C |
| Automotive | MC/DC for ASIL D | ISO 26262 |
| Medical | 100% Branch minimum | IEC 62304 |
| Financial | 80%+ Branch | SOX compliance |
| General software | 70-80% Line/Branch | Industry practice |
⚠️
Exam Tip: Know the subsumption relationships. If a question asks what achieving 100% branch coverage guarantees, remember it guarantees 100% statement coverage but NOT 100% condition coverage.
Practical Application and Tool Integration
Common Coverage Tools
| Language | Tools |
|---|---|
| Java | JaCoCo, Cobertura, Emma |
| Python | Coverage.py, pytest-cov |
| JavaScript | Istanbul/nyc, Jest coverage |
| C/C++ | gcov, lcov, BullseyeCoverage |
| .NET | dotCover, OpenCover, Coverlet |
Coverage in CI/CD Pipelines
# Example GitHub Actions coverage workflow
name: Coverage
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Run tests with coverage
run: |
pytest --cov=src --cov-report=xml
coverage report --fail-under=80Interpreting Coverage Reports
Sample JaCoCo Report Metrics:
| Metric | Meaning |
|---|---|
| Instructions | Low-level bytecode coverage |
| Branches | Decision point coverage |
| Lines | Source line coverage |
| Complexity | Cyclomatic complexity covered |
| Methods | Method entry coverage |
| Classes | Class instantiation coverage |
Coverage Limitations to Remember
Coverage does not guarantee:
- Correct expected values in assertions
- All boundary conditions tested
- Non-functional requirements met
- All integration scenarios covered
- Absence of bugs
High coverage with weak assertions provides false confidence.
Test Your Knowledge
Quiz on CTAL-TTA White-Box Techniques
Your Score: 0/10
Question: A function contains 50 executable statements. During testing, 40 statements were executed. What is the statement coverage?
Continue Your Certification Journey
Frequently Asked Questions
Frequently Asked Questions (FAQs) / People Also Ask (PAA)
What is the difference between statement coverage and branch coverage?
Why is MC/DC preferred over Multiple Condition Coverage in practice?
How do I calculate cyclomatic complexity and what does it indicate?
What is data flow testing and when should I use it?
Can I achieve 100% condition coverage without achieving 100% branch coverage?
What tools measure code coverage and how do I use them?
What is the subsumption hierarchy of coverage criteria?
How does white-box testing complement black-box testing?