ISTQB Certifications
Technical Test Analyst (CTAL-TTA)
Advanced White-Box Techniques

CTAL-TTA White-Box Test Techniques: Complete Coverage Analysis Guide

Parul Dhingra - Senior Quality Analyst
Parul Dhingra13+ Years ExperienceHire Me

Senior Quality Analyst

Updated: 1/25/2026

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.

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:

AspectDescription
BasisSource code, control flow, data flow
VisibilityFull access to internal implementation
GoalExercise code structures systematically
MeasurementCoverage 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: Exit

Control 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:

LevelNameDescriptionSubsumes
C0StatementEvery statement executed-
C1Branch/DecisionEvery branch takenC0
C2ConditionEvery condition outcome-
C3Condition/DecisionC1 + C2 combinedC1, C2
MC/DCModified Condition/DecisionIndependence shownC3
MCCMultiple ConditionAll combinationsMC/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                           # S8

Statement Count: 8 executable statements (S1-S8)

Test for 100% Statement Coverage:

Testweightis_expressis_memberStatements Executed
T115TrueTrueS1, 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 discount

A 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_cost

Total Branches: 6 (2 per decision × 3 decisions)

Tests for 100% Branch Coverage:

Testweightis_expressis_memberD1D2D3
T115TrueTrueTrueTrueTrue
T25FalseFalseFalseFalseFalse

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 False

To 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 body

Branch 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 False

Tests for 100% Condition Coverage:

Testamountis_new_customerA (amount > 1000)B (is_new_customer)
T11500FalseTrueFalse
T2500TrueFalseTrue

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 False

Tests for 100% Condition/Decision Coverage:

Testamountis_new_customerABDecision
T11500FalseTrueFalseTrue
T2500TrueFalseTrueTrue
T3500FalseFalseFalseFalse

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:

  1. Every entry and exit point is invoked
  2. Every decision takes all possible outcomes
  3. Every condition takes all possible outcomes
  4. 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:

TestABA and B
1TTT
2TFF
3FTF
4FFF

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):

#ABC(A or B)(A or B) and C
1TTTTT
2TTFTF
3TFTTT
4TFFTF
5FTTTT
6FTFTF
7FFTFF
8FFFFF

Finding Independence Pairs:

ConditionIndependence PairEffect
ATests 3 & 7A: T→F, B=F, C=T, Decision: T→F
BTests 5 & 7B: T→F, A=F, C=T, Decision: T→F
CTests 3 & 4C: 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:

StandardIndustryMC/DC Requirement
DO-178C Level AAviationRequired
ISO 26262 ASIL DAutomotiveRequired
IEC 62304 Class CMedical DevicesRecommended
EN 50128 SIL 4RailwayRequired

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^N

Example

if (A and B and C):
    action()

Required Tests: 2^3 = 8 test cases

TestABCDecision
1TTTT
2TTFF
3TFTF
4TFFF
5FTTF
6FTFF
7FFTF
8FFFF

Practical Limitations

Exponential Growth Problem:

ConditionsMCC TestsMC/DC Tests
243
384
4165
5326
101,02411

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:

TermDefinitionExample
Definition (def)Variable assigned a valuex = 5
Use (use)Variable value is ready = x + 1
C-useComputational use in calculationresult = x * 2
P-usePredicate use in conditionif x > 0:
KillVariable undefined/out of scopeEnd 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 7

Du-pairs for total:

DefinitionUseType
Line 2Line 3p-use
Line 2Line 5c-use
Line 2Line 6c-use (if condition false)
Line 5Line 6c-use (if condition true)
Line 2Line 7c-use (if condition false)
Line 5Line 7c-use (if condition true)

Data Flow Coverage Criteria

From weakest to strongest:

CriterionRequirement
All-defsEach definition reaches at least one use
All-usesEach definition reaches all possible uses
All-du-pathsEvery path from definition to use is tested

Data Flow Anomalies

Data flow analysis detects anomalies:

AnomalyPatternProblem
uruse before definitionUsing uninitialized variable
dddefinition followed by definitionFirst definition wasted
dudefinition followed by killDefined 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 Coverage

Choosing the Right Coverage Level

ScenarioRecommended CoverageRationale
Safety-critical systemsMC/DCRegulatory requirement, high rigor
Financial transactionsBranch + ConditionBalance of rigor and practicality
Standard business logicBranch coverageGood defect detection
Legacy code maintenanceStatement coverageBaseline assurance
Quick smoke testingStatement coverageRapid feedback

Coverage Goals by Industry

IndustryTypical TargetStandard
Aviation100% MC/DCDO-178C
AutomotiveMC/DC for ASIL DISO 26262
Medical100% Branch minimumIEC 62304
Financial80%+ BranchSOX compliance
General software70-80% Line/BranchIndustry 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

LanguageTools
JavaJaCoCo, Cobertura, Emma
PythonCoverage.py, pytest-cov
JavaScriptIstanbul/nyc, Jest coverage
C/C++gcov, lcov, BullseyeCoverage
.NETdotCover, 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=80

Interpreting Coverage Reports

Sample JaCoCo Report Metrics:

MetricMeaning
InstructionsLow-level bytecode coverage
BranchesDecision point coverage
LinesSource line coverage
ComplexityCyclomatic complexity covered
MethodsMethod entry coverage
ClassesClass 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?