A Definition-Use Pair (DU Pair) is a concept in data flow testing that connects the definition of a variable (where it is assigned a value) to its usage (where that value is read).
Use (u): Computation, condition, output (e.g., y = x + 1, if (x > 0)).
Definition-Clear Path
A path d→⋯→u is definition-clear for v if no other node on the path re-defines v. If v were re-defined at node k (where d→⋯→k→⋯→u), then the use at u would rely on the value from k, not d.
Reaching Definitions Analysis
DU pairs are computed with a reaching-definitions static analysis. For each node n and variable v, it computes all definitions of v that possibly reach n via a definition-clear path.
Definitions:
pred(n)={m∣(m,n,c)∈ECFG}: Predecessors of n.
succ(m)={n∣(m,n,c)∈ECFG}: Successors of m.
gen(n)={vn∣n is a definition for v}: Definitions generated in n.
kill(n)={vm∣n is a definition for v∧m=n}: Definitions killed in n.
Algorithm (Fixpoint Iteration): We compute two sets for every node:
Reach(n): The reaching definitions at the beginning of n.
Reach(n)=m∈pred(n)⋃ReachOut(m)
ReachOut(n): The reaching definitions at the end of n.
ReachOut(n)=(Reach(n)∖kill(n))∪gen(n)
Metrics
DU-Pairs Coverage
The percentage of all feasible valid DU pairs that are exercised by the test suite.
DU-PairsCoverage=Total number of DU pairsNumber of executed DU pairs×100%
Strength: Stronger than branch coverage and can be equivalent to path coverage in specific cases, but generally more focused on data dependencies.
Example
Example: Simple
1: x = 1;2: y = 1;3: if (a) {4: x = 0;5: }6: return x;
DU Pairs for x:
Def at 1:x = 1 reaches usage at 6 if path is 1→2→3→5→6 (Branch a is False).
Pair: (1,6).
Def at 4:x = 0 reaches usage at 6 if path is 1→2→3→4→5→6 (Branch a is True).
Pair: (4,6).
DU Pairs for y:
Def at 2:y = 1.
Use: None.
Result: No DU pairs for y.
Coverage Analysis: To achieve 100% DU-Pairs Coverage for x, we need a test where a is True (executes pair (4,6)) and a test where a is False (executes pair (1,6)).
Example: Invoice Calculation
Exercise 5: Data Flow Coverage
You are given the following function calculateInvoice and an initial test suite.
01 int calculateInvoice(int items, boolean isVIP) {02 int total = 0; // d103 int surcharge = 0; // d50405 for (int i = 1; i <= items; i++) {06 total += 100; // d20708 if (i % 3 == 0) {09 surcharge += 20; // d610 } else {11 surcharge += 10; // d712 }13 }1415 if (isVIP) {16 total = total - 50; // d317 }1819 total += surcharge; // d420 return total;21 }
Initial Tests:
T1:items = 0, isVIP = false
T2:items = 1, isVIP = false
a) Control Flow Graph (CFG):
We define the following Basic Blocks (BB):
BB0 (Entry): Lines 1-5 (initialisation).
BB1 (Loop Header): Line 5 (condition i <= items).
BB2 (Loop Body Start): Line 6 (total += 100) and 8 (condition i % 3 == 0).
BB3 (If True): Line 9 (surcharge += 20).
BB4 (If False): Line 11 (surcharge += 10).
BB5 (Loop Increment): Line 5 (i++).
BB6 (After Loop): Line 15 (condition isVIP).
BB7 (VIP Branch): Line 16 (total -= 50).
$BB8 (Exit): Line 19 (total += surcharge) and 20 (return).
4. Feasibility:
Achieving 100% DU-pair coverage is not always possible due to infeasible paths. In this example, pairs like (3,9) and (9,9) are infeasible because the logic (i%3==0) and the loop counter initialization prevent those specific definition-use combinations from ever being executed.