The Importance of Graph Based Test The findings can help the testers during the unit test to choose which criteria, when can be used. The Importance of Test Path A test path represents the execution of a test case on a graph. Test paths must start at an initial node and end at a final node. A test path p tours a subpath q if q is a subpath of p. Simple Path A path from node ni to nj is simple if no node appears more than once in the path, But the first and last nodes may be identical. In other words; Simple paths have no internal loops, But the entire path itself may be a loop. Example Simple Paths = {[1] ,[2], [3], [4] ,[5] [6], [1 ,2], [2,3], [2,4] [3,5] [3,6] [5, 2], [1, 2,3] , [1, 2,4] [2, 3,5] [2,3,6], [3, 5, 2], [5, 2, 3], [5, 2, 4], [1, 2, 3, 6], [1, 2, 3, 5], [2, 3, 5, 2], [3, 5, 2, 3], [3, 5, 2, 4], [5, 2, 3, 6], [5, 2, 3, 5] } 1 2 4 3 5 6 4 Example Edge-Pairs = { [1, 2, 3], [1, 2, 4], [2, 3, 5], [2, 3, 6], [3, 5, 2], [5, 2, 3], [5, 2, 4] } 1 2 3 5 4 6 5 Prime Path Prime paths are maximal length simple paths A simple path from node ni to nj is a prime path if it is simple and does not appear as a proper subpath of any other simple path. Prime paths do not have any internal loops, But the entire path may be a loop. Prime Paths = { [n0, n1, n3], [n0, n2, n3] } path (t1) = [n0, n1, n3] path (t2) = [n0, n2, n3] T1 = {t1, t2} T1 satisfies prime path coverage on the graph Prime Paths = { [n0, n1, n2], [n0, n1, n3, n4], [n1, n3, n4, n1], [n3, n4, n1, n3], [n4, n1, n3, n4], [n3, n4, n1, n2] } path (t3) = [n0, n1, n2] path (t4) = [n0, n1, n3, n4, n1, n3, n4, n1, n2] T2 = {t3, t4} T2 satisfies prime path coverage on the graph The Importance of Prime Path Coverage In prime path coverage, tests must tour each prime path in the graph G. Prime path coverage requires touring all subpaths of length 0 (all nodes), of length 1 (all edges), length 2, 3, etc. Therefore This coverage includes node coverage, edge coverage and edge-pair coverage. Example Prime Paths = { [1, 2, 4], [1, 2, 3, 6], [1, 2, 3, 5], [2, 3, 5, 2], [3, 5, 2, 3], [3, 5, 2, 4], [5, 2, 3, 6], [5, 2, 3, 5] } 1 2 3 5 4 6 9 Edge-Pair Coverage Tests must tour each reachable subpath of length less than or equal to 2 in G. Edge-pair coverage subsumes edge coverage and node coverage in graphs that have only one edge or only one node Example Edge-Pairs = { [1, 2, 3], [1, 2, 4], [2, 3, 5], [2, 3, 6], [3, 5, 2], [5, 2, 3], [5, 2, 4] } 1 2 3 5 4 6 11 Structural Based Test Criteria in Unit Testing The edge-pair and prime path criteria are defined on unannotated graphs; The graphs are usually control flow graphs of the methods. The Application of Graph Criteria: Source Code It is usually defined with the control flow graph (CFG) Node coverage is used to execute every statement Edge coverage is used to execute every branch Loops are used to execute looping structures such as for loops, while loops, etc. Data flow coverage is the extended form of control flow graph (CFG) with defs and uses defs are statements that assign values to variables uses are statements that use variables Control Flow Graphs : The if Statement if (x < y) { y = 0; x = x + 1; } else { x = y; } 1 x<y y=0 x=x+1 x >= y 2 3 x=y 4 if (x < y) { y = 0; x = x + 1; } 1 x<y y=0 x=x+1 2 x >= y 3 14 Control Flow Graphs : The if-Return Statement if (x < y) { return; } print (x); return; 1 x<y return 2 x >= y 3 print (x) return 15 Control Flow Graphs : while and for Loops x=0 x = 0; while (x < y) { y = f (x, y); x = x + 1; } 1 for (x = 0; x < y; x++) { y = f (x, y); } 2 x<y x3< y x >= y x4>= y y =f(x,y) x=x+1 1 2 x<y y = f (x, y) 3 4 x >= y 5 x=x+1 16 Control Flow Graphs : do Loop, break and continue 1 x=0 x = 0; do { y = f (x, y); x = x + 1; } while (x < y); println (y) x=0 1 2 x >= y 3 y = f (x, y) x = x+1 x<y x = 0; while (x < y) { y = f (x, y); if (y == 0) { break; } else if y < 0) { y = y*2; continue; } x = x + 1; } print (y); 2 3 y =f(x,y) y == 0 4 break 5 y<0 6 7 y = y*2 continue x=x+1 8 17 Tests with Data Flow Criteria Data flow criteria require tests that tour subpaths from specific definitions of variables to specific uses Nodes where a variable is assigned a value are called definitions (or defs) Nodes where the value of a variable is accessed are called uses. Data Flow Coverage for Source def : A location where a value is stored into memory x appears on the left side of an assignment (x = 44; x is an actual parameter in a call and the method changes its value x is a formal parameter of a method (implicit def when method starts) x is an input to a program use : A location where variable’s value is accessed x appears on the right side of an assignment x appears in a conditional test x is an actual parameter to a method x is an output of the program x is an output of a method in a return statement If a def and a use appear on the same node, then it is only a DU-pair 19 A definition d for a variable x reaches a use u if there is a path from d to u that has no other definitions of x (def-clear). The all-uses (AU) criterion requires tests to tour at least one subpath from each definition to each reachable use. // EXAMPLE: return index of the last element in x that equals y. // if y is not in x, return -1. public int findLast (int []x, int y) { for (int i = x.length-1; i>=0; i--) { if (x[i] == y) return i; } return -1; Annotated Control Graph Nodes 4 and 6 are final nodes, corresponding to the return statements. Node 2 is introduced to capture the for loop; it has no executable use(3)= statements. DU (def-use) pairs are shown as a variable name followed by the def node, then the use node. def (5) = { i } use (5) = { i } Def -Use Pairs = { (1, 1,x), (1,3,x), (1,3,y), (1, 2,i), (1, 3,i), (1,5,i), (1,6,i), (5, 2,i), (5, 3,i), ( 5, 6,i), (5, 5,i)} public static void computeStats (int [ ] numbers) { int length = numbers.length; double med, var, sd, mean, sum, varsum; sum = 0; for (int i = 0; i < length; i++) { sum += numbers [ i ]; } med = numbers [ length / 2]; mean = sum / (double) length; 1 2 i=0 3 varsum = 0; for (int i = 0; i < length; i++) 4 { 5 varsum = varsum + ((numbers [ I ] - mean) * (numbers [ I ] - mean)); i=0 } var = varsum / ( length - 1.0 ); sd = Math.sqrt ( var ); 6 System.out.println ("length: " + length); i < length System.out.println ("mean: " + mean); i >= length System.out.println ("median: " + med); 7 System.out.println ("variance: " + var); 8 System.out.println ("standard deviation: " + sd); } i++ 22 Edge Coverage 1 TR = {[ 1, 2 ],[ 2, 3 ],[ 3, 4 ], [ 3, 5 ], [ 4, 3 ], [ 5, 6 ], [ 6, 7 ], [ 6, 8 ],[ 7, 6 ]} 2 3 4 5 Test Path , 3, 4, 3, 5, 6, 7, 6, 8 ] [ 1, 2, 3,4, 3, 5, 6, 7, 6, 8] ] 6 7 8 23 Edge-Pair Coverage TR={ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 2, 3, 5 ], [ 3, 4, 3 ], [ 3, 5, 6 ], [ 4, 3, 5 ],[ 5, 6, 7 ],[ 5, 6, 8 ], [ 6, 7, 6 ], [ 7, 6, 8 ], [ 4, 3, 4 ], [ 7, 6, 7 ]} Test Paths i.[ 1, 2, 3, 4, 3, 5, 6, 7, 6, 8 ] ii. [ 1, 2, 3, 5, 6, 8 ] iii. [ 1, 2, 3, 4, 3, 4, 3, 5, 6, 7, 6, 7, 6, 8 ] Test Requirements Toured i.[ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 3 ], [ 3, 5, 6 ], [ 4, 3, 5 ], [ 5, 6, 7] , [ 6, 7, 6 ], [ 7, 6, 8 ] ii. [ 1, 2, 3 ], [ 2, 3, 5 ], [ 3, 5, 6 ], [ 5, 6, 8 ] iii. [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4, 3 ], [ 3, 5, 6 ], [ 4, 3, 5 ], [ 5, 6, 7 ],[ 6, 7, 6 ],[ 7, 6, 8 ], [ 4, 3, 4 ], [ 7, 6, 7 ] 24 Prime Path Coverage TR={ [ 3, 4, 3 ],[ 4, 3, 4 ],[ 7, 6, 7 ], [ 7, 6, 8 ], [ 6, 7, 6 ], [ 1, 2, 3, 4 ], [ 4, 3, 5, 6, 7 ], [ 4, 3, 5, 6, 8 ], [ 1, 2, 3, 5, 6, 7 ], [ 1, 2, 3, 5, 6, 8 ]} Test Paths i. [ 1, 2, 3, 4, 3, 5, 6, 7, 6, 8 ] ii. [ 1, 2, 3, 4, 3, 4, 3, 5, 6, 7, 6, 7, 6, 8 ] iii. [ 1, 2, 3, 4, 3, 5, 6, 8 ] iv. [ 1, 2, 3, 5, 6, 7, 6, 8 ] v. [ 1, 2, 3, 5, 6, 8 ] Test Requirements Toured i. [ 3, 4, 3 ], [ 7, 6, 8 ], [ 6, 7, 6 ], [ 1, 2, 3, 4 ], [ 4, 3, 5, 6, 7 ] ii. [ 3, 4, 3 ], [ 4, 3, 4 ], [ 7, 6, 7 ], [ 7, 6, 8 ], [ 6, 7, 6 ], [ 1, 2, 3, 4 ] [ 4, 3, 5, 6, 7 ] iii. [ 3, 4, 3 ], [ 1, 2, 3, 4 ], [ 4, 3, 5, 6, 8 ] iv. [ 7, 6, 8 ], [ 6, 7, 6 ], [ 1, 2, 3, 4 ], [ 1, 2, 3, 5, 6, 7 ] v. . [ 1, 2, 3, 5, 6, 8 ] 25 Control Flow Graph for ComputeStats 1 ( numbers ) sum = 0 length = numbers.length 2 i=0 3 i >= length i < length 4 5 sum += numbers [ i ] i++ med = numbers [ length / 2 ] mean = sum / (double) length varsum = 0 i=0 6 i >= length i < length varsum = … i++ 7 8 var = varsum / ( length - 1.0 ) sd = Math.sqrt ( var ) print (length, mean, med, var, sd) 26 CFG for ComputeStats – With Defs & Uses 1 def (1) = { numbers, sum, length } 2 def (2) = { i } 3 use (3, 5) = { i, length } use (3, 4) = { i, length } 4 def (4) = { sum, i } use (4) = { sum, numbers, i } 5 6 def (5) = { med, mean, varsum, i } use (5) = { numbers, length, sum } use (6, 8) = { i, length } use (6, 7) = { i, length } 7 def (7) = { varsum, i } use (7) = { varsum, numbers, i, mean } 8 def (8) = { var, sd } use (8) = { varsum, length, mean, med, var, sd } 27 Defs and Uses Tables for ComputeStat Node 1 2 3 4 5 Def Use { numbers, sum, length } {i} { numbers } { sum, i } { med, mean, varsum, i } { numbers, i, sum } { numbers, length, sum } 8 { varsum, i } { var, sd } Use (1, 2) (2, 3) (3, 4) (4, 3) { i, length } (3, 5) { i, length } (5, 6) 6 7 Edge { varsum, numbers, i, mean } { varsum, length, var, mean, med, var, sd } (6, 7) { i, length } (7, 6) (6, 8) { i, length } 28 DU Pairs for ComputeStat variable DU Pairs Defs come before uses, do not count as DU pairs numbers (1, 4) (1, 5) (1, 7) length (1, 5) (1, 8) (1, (3,4)) (1, (3,5)) (1, (6,7)) (1, (6,8)) med var sd mean sum varsum i (5, 8) defs after use in loop, these (8, 8) are valid DU pairs (8, 8) (5, 7) (5, 8) No def-clear path … (1, 4) (1, 5) (4, 4) (4, 5) different scope for i (5, 7) (5, 8) (7, 7) (7, 8) (2, 4) (2, (3,4)) (2, (3,5)) (2, 7) (2, (6,7)) (2, (6,8)) (4, 4) (4, (3,4)) (4, (3,5)) (4, 7) (4, (6,7)) (4, (6,8)) (5, 7) (5, (6,7)) (5, (6,8)) No path through graph from (7, 7) (7, (6,7)) (7, (6,8)) nodes 5 and 7 to 4 or 3 29 DU Paths for Stats variable numbers length med var sd sum DU Pairs DU Paths (1, 4) (1, 5) (1, 7) [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 7 ] (1, 5) (1, 8) (1, (3,4)) (1, (3,5)) (1, (6,7)) (1, (6,8)) [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 8 ] [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 7 ] [ 1, 2, 3, 5, 6, 8 ] (5, 8) (8, 8) (8, 8) (1, 4) (1, 5) (4, 4) (4, 5) [ 5, 6, 8 ] No path needed No path needed [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 4, 3, 4 ] [ 4, 3, 5 ] variable mean DU Pairs (5, 7) (5, 8) DU Paths [ 5, 6, 7 ] [ 5, 6, 8 ] varsum (5, 7) (5, 8) (7, 7) (7, 8) [ 5, 6, 7 ] [ 5, 6, 8 ] [ 7, 6, 7 ] [ 7, 6, 8 ] i (2, 4) (2, (3,4)) (2, (3,5)) (4, 4) (4, (3,4)) (4, (3,5)) (5, 7) (5, (6,7)) (5, (6,8)) (7, 7) (7, (6,7)) (7, (6,8)) [ 2, 3, 4 ] [ 2, 3, 4 ] [ 2, 3, 5 ] [ 4, 3, 4 ] [ 4, 3, 4 ] [ 4, 3, 5 ] [ 5, 6, 7 ] [ 5, 6, 7 ] [ 5, 6, 8 ] [ 7, 6, 7 ] [ 7, 6, 7 ] [ 7, 6, 8 ] 30 DU Paths for ComputeStats – No Duplicates There are 38 DU paths for ComputeStats, but only 12 unique [ 1, 2, 3, 4 ] [ 1, 2, 3, 5 ] [ 1, 2, 3, 5, 6, 7 ] [ 1, 2, 3, 5, 6, 8 ] [ 2, 3, 4 ] [ 2, 3, 5 ] [ 4, 3, 4 ] [ 4, 3, 5 ] [ 5, 6, 7 ] [ 5, 6, 8 ] [ 7, 6, 7 ] [ 7, 6, 8 ] 4 expect a loop not to be “entered” 6 require at least one iteration of a loop 2 require at least two iterations of a loop 31 Test Cases and Test Paths Test Case : numbers = (44) ; length = 1 Test Path : [ 1, 2, 3, 4, 3, 5, 6, 7, 6, 8 ] Additional DU Paths covered (no sidetrips) [ 1, 2, 3, 4 ] [ 2, 3, 4 ] [ 4, 3, 5 ] [ 5, 6, 7 ] [ 7, 6, 8 ] The five stars that require at least one iteration of a loop Test Case : numbers = (2, 10, 15) ; length = 3 Test Path : [ 1, 2, 3, 4, 3, 4, 3, 4, 3, 5, 6, 7, 6, 7, 6, 7, 6, 8 ] DU Paths covered (no sidetrips) [ 4, 3, 4 ] [ 7, 6, 7 ] The two stars that require at least two iterations of a loop Other DU paths require arrays with length 0 to skip loops But the method fails with index out of bounds exception… med = numbers [length / 2]; A fault was found 32