LECTURE 7: SOFTWARE TESTING
WHITE BOX TESTING
1
White-box Testing
White Box Testing is a testing technique which evaluates the code and
the internal structure of a program.
It is one of the most used software testing techniques.
Designing white-box test cases:
– requires knowledge about the internal structure of software.
– white-box testing is also called structural testing.
There exist several popular white-box testing methodologies:
1. Statement coverage
2. branch coverage
3. path coverage
4. condition coverage
5. mutation testing
6. data flow-based testing
2
Statement Coverage
Statement coverage testing: In this the test case is executed in such a
way that every statement of the code is executed at least once.
Example
1.print (int a, int b) {
2.int sum;
3.sum = a+b;
4.if (sum>0)
5.print ("This is a positive result")
6.else
7.print ("This is negative result")
8.}
If a = 5, b = 4, So the Statement coverage = 5/7*100 = 71%
3
Branch Coverage
Branch coverage is a testing method, is used to cover all branches of the
control flow graph.
1.Read X
2.Read Y Control flow graph of code
structure
3.IF X+Y > 100 THEN
4.Print "Large"
5.ENDIF
6.If X + Y<100 THEN
7.Print "Small"
8.ENDIF
Path 1 - A1-B2-C4-D6-E8
Path 2 - A1-B3-5-D7
Branch Coverage (BC) = Number of paths =2
Case Covered Branches Path Branch coverage
Yes 1, 2, 4, 5, 6, 8 A1-B2-C4-D6-E8 2
No 3,7 A1-B3-5-D7 4
Path Coverage
A path through a program:
– a node and edge sequence from the starting node to a terminal node of
the control flow graph.
– There may be several terminal nodes for program.
Design test cases such that:
– all linearly independent paths in the program are executed at least once.
Linearly independent paths
Is any path through the program that introduces at least one new edge or
node that is not included in any other linearly independent paths.
Defined in terms of: control flow graph (CFG) of a program.
Path coverage-based testing
To understand the path coverage-based testing: we need to learn how to draw
control flow graph of a program.
5
Control flow graph (CFG)
A control flow graph (CFG) describes:
1. The sequence in which different instructions of a program get executed.
2. How the control flows through the program.
How to draw Control flow graph?
1. Number all the statements of a program.
2. Numbered statements: represent nodes of the control flow graph.
3. An edge from one node to another node exists: if execution of the statement
representing the first node, can result in transfer of control to the other node.
6
How to draw Control flow graph?
Sequence: 1
– 1 a=5;
– 2 b=a*b-1;
2
Selection:
– 1 if(a>b) then 1
– 2 c=3; 2 3
– 3 else c=5;
– 4 c=c*c; 4
1
Iteration:
– 1 while(a>b){
– 2 b=b*a; 2
– 3 b=b-1;}
– 4 c=b+d;
3
4
Example
int f1(int x,int y){
1
1 while (x != y){
2 if (x>y) then 2
3 x=x-y; 3 4
4 else y=y-x;
5
5 }
6 return x; } 6
It is straight forward to identify linearly independent paths of simple
programs.
For complicated programs: it is not so easy to determine the number of
independent paths.
8
McCabe's Cyclomatic complexity metric
Is a software metric used to indicate the complexity of a program. It is a
quantitative measure of the number of linearly independent paths through a
program's source code.
It is computed using the control flow graph of the program: the nodes of the
graph correspond to indivisible groups of commands of a program.
To test each linearly independent path through the program; the number of
test cases will equal the cyclomatic complexity of the program.
Given a control flow graph G, the cyclomatic complexity can be computed in
two ways:
1. V(G) = E-N+2P
‾ N is the number of nodes in G
‾ E is the number of edges in G
‾ P = the number of connected components [always 1 for a single program]
2. V (G) = P + 1
‾ P = Number of predicate nodes (node that contains condition)
9
Example Control Flow Graph
1
2
3 4
5
6
Cyclomatic complexity
V(G) = M = 7-6+2 = 3.
V(G) = 2 + 1 = 3.
10
Cyclomatic complexity
McCabe's metric provides: quantitative measure of testing difficulty
The first method of computing V(G) is amenable to automation:
– You can write a program which determines the number of nodes and
edges of a graph
– Applies the formula to find V(G).
The cyclomatic complexity of a program provides:
– The number of independent paths in a program
– A lower bound on the number of test cases to be designed
– To guarantee coverage of all linearly independent paths.
Knowing the number of test cases required:
– does not make it any easier to derive the test cases,
– only gives an indication of the minimum number of test cases required.
11
Path testing
The tester proposes:
– an initial set of test data using his experience and judgement.
Derivation of Test Cases
Let us discuss the steps: to derive path coverage test cases of a program.
Draw control flow graph.
Determine V(G).
Determine the set of linearly independent paths.
Prepare test cases: to force execution along each path.
12
Example
int f1(int x,int y){ 1
1 while (x != y){ 2
2 if (x>y) then
3 4
3 x=x-y;
4 else y=y-x; 5
5 } 6
6 return x; }
Number of independent paths: 3
– 1,6 test case (x=1, y=1)
– 1,2,3,5,1,6 test case(x=1, y=2)
– 1,2,4,5,1,6 test case(x=2, y=1)
13
An interesting application of cyclomatic complexity
Relationship exists between:
– McCabe's metric
– the number of errors existing in the code,
– the time required to find and correct the errors.
Cyclomatic complexity of a program:
– also indicates the psychological complexity of a program.
– difficulty level of understanding the program.
From maintenance perspective,
– limit cyclomatic complexity of modules to some reasonable value.
– Good software development organizations: restrict cyclomatic
complexity of functions to a maximum of ten or so.
14
Basis Path Testing
First, we compute the cyclomatic complexity:
Number of edges – number of nodes + 2
9-7 + 2 = 4 or number of simple decisions + 1 or
Number of enclosed areas + 1 In this case, V(G) = 4
Next, we derive the independent paths:
Since V(G) = 4, there are four paths
Path 1: 1,2,3,6,7,8
Path 2: 1,2,3,5,7,8
Path 3: 1,2,4,7,8
Path 4: 1,2,4,7,2,4,...7,8
Finally, we derive test cases to test these paths.
15
Simple
loop
Nested
Loops
Concatenated
Loops Unstructured
Loops
Loop Testing
16
Simple Loops
1. skip the loop entirely
2. only one pass through the loop
3. two passes through the loop
4. m passes through the loop m < n
5. (n-1), n, and (n+1) passes through the loop where n is the maximum
number of allowable passes
Nested Loops
1. Start at the innermost loop. Set all outer loops to their minimum iteration
parameter values.
2. Test the min+1, typical, max-1 and max for the innermost loop, while
holding the outer loops at their minimum values.
3. Move out one loop and set it up as in step 2, holding all
4. other loops at typical values. Continue this step until
5. the outermost loop has been tested.
Concatenated Loops
If the loops are independent of one another then treat each as a simple loop
else* treat as nested loops
endif*
for example, the final loop counter value of loop 1 is used to initialize loop 2. 17
White-box Testing Example
FindMean(float Mean, FILE ScoreFile)
{ SumOfScores = 0.0; NumberOfScores = 0; Mean = 0;
Read(ScoreFile, Score);
/*Read in and sum the scores*/
while (! EOF(ScoreFile) {
if ( Score > 0.0 ) {
SumOfScores = SumOfScores + Score; NumberOfScores++;
}
Read(ScoreFile, Score);
}
/* Compute the mean and print the result */
if (NumberOfScores > 0 ) {
Mean = SumOfScores/NumberOfScores;
printf("The mean score is %f \n", Mean);
} else
}
printf("No scores found in file\n");
}
18
Determining the Paths
19
Constructing the Flow Graph
Finding the Test Cases
20
Structural Coverage Criteria: Control Flow
Structural Testing: Examples
Path testing
Visit-each-loop path testing
Branch testing
Statement testing 21
Infeasible paths
The simple code can have four total test paths: TP1: 1,2,4,6,8,10, TP2:
1,2,4,7,9,10, TP3: 1,3,5,6,8,10, TP4: 1,3,5,7,9,10. According to the two
conditional statements and due to the contradicted logic of the two
conditions, we can easily notice that TP1 can never be executed and
hence will be always infeasible paths.
22
Summary
Exhaustive testing of non-trivial systems is impractical:
– we need to design an optimal set of test cases
• should expose as many errors as possible.
If we select test cases randomly:
– many selected test cases don’t add to the significance of the test set.
There are mainly two approaches to testing:
– black-box testing and
– white-box testing.
White box testing:
– requires knowledge about internals of the software.
– Design and code is required.
A stronger testing strategy:
– provides more number of significant test cases than a weaker one.
– Condition coverage is strongest among strategies we discussed.
Designing test cases for black box testing:
– does not require any knowledge of how the functions have been designed
and implemented.
– Test cases can be designed by examining only SRS document.
23
References
Bernd Bruegge & Allen H. Dutoit, Object-Oriented Software
Engineering: Using UML, Patterns, and Java
Software Engineering, Ivan Marsic, 2020
Sommerville, I. (2015). Software Engineering 10. Pearson.