EXP-9 Estimation of Test Coverage Metrics and Structural Complexity
EXP-9 Estimation of Test Coverage Metrics and Structural Complexity
Introduction
In this experiment, we will learn about basic blocks and how to draw a CFG using
them. We would look into paths and linearly independent paths in context of a
CFG. Finally, we would learn about McCabe's cyclomatic complexity, and classify a
given program based on that.
Objectives
Identify basic blocks in a program module, and draw it's control flow graph
(CFG)
Time Required
Around 3.00 hours
A control flow graph (CFG) is a directed graph where the nodes represent
different instructions of a program, and the edges define the sequence of
execution of such instructions. Figure 1 shows a small snippet of code (compute
the square of an integer) along with it's CFG. For simplicity, each node in the CFG
has been labeled with the line numbers of the program containing the
instructions. A directed edge from node #1 to node #2 in figure 1 implies that
after execution of the first statement, the control of execution is transferred to
the second instruction.
x_2 = x * x;
return x_2;
A real life application seldom could be written in a few lines. In fact, it might
consist of thousand of lines. A CFG for such a program is likely to become very
large, and it would contain mostly straight-line connections. To simplify such a
graph different sequential statements could be grouped together to form a basic
block. A basic block is a [ii, iii] maximal sequence of program instructions I1, I2, ...,
In such that for any two adjacent instructions Ik and Ik+1, the following holds true:
The size of a CFG could be reduced by representing each basic block with a node.
To illustrate this, let's consider the following example.
sum = 0;
i = 1;
while (i ≤ n) {
sum += i;
++i;
}
printf("%d", sum);
if (sum > 0) {
printf("Positive");
The CFG with basic blocks is shown for the above code in figure 3.
If any block (or sub-graph) in a CFG is not connected with the sub-graph
containing the entry block, that signifies the concerned block contains code,
which is unreachable while the program is executed. Such unreachable code can
be safely removed from the program. To illustrate this, let's consider a modified
version of our previous code:
sum = 0;
i = 1;
while (i ≤ n) {
sum += i;
++i;
return sum;
if (sum < 0) {
return 0;
Terminologies
Path
A path in a CFG is a sequence of nodes and edges that starts from the initial node
(or entry block) and ends at the terminal node. The CFG of a program could have
more than one terminal nodes.
1 - 3 - 6 - (7, 8) - 10
1 - 3 - 6 - (7, 8) - 9 - 10
1 - 3 - (4, 5) - 6 - (7, 8) - 10
1 - 3 - (4, 5) - 6 - (7, 8) - 9 - 10
Note that 1 - 3 - (4, 5) - 3 - (4, 5) - 6 - (7, 8) - 10, for instance, won't qualify as a
linearly independent path because there is no new edge not already present in
any of the above four linearly independent paths.
Method #1:V(G) = E - N + 2
A set of threshold values for Cyclomatic complexity has been presented in [vii],
which we reproduce below.
It has been suggested that the Cyclomatic complexity of any module should not
exceed 10 [vi], [4]. Doing so would make a module difficult to understand for
humans. If any module is found to have Cyclomatic complexity greater than 10,
the module should be considered for redesign. Note that, a high value of V(G) is
possible for a given module if it contains multiple cases in C like switch-
case statements. McCabe had exempted such modules from the limit of V(G) as
10 [vi].
Merits
while (x != y) {
if (x > y)
x = x - y;
else
y = y - x;
return x;
Method #1
N = No. of nodes = 7
E = No. of edges = 8
V(G) = E - N + 2 = 8 - 7 + 2 = 3
Method #2
V(G) = Total no. of non overlapping areas + 1 = 2 + 1 = 3
ID transactionID = null;
user.incrementReissueCount(bookID);
transaction.save();
transactionID = transaction.getID();
return transactionID;
The Control Flow Graph for the above module is shown in figure 1. The CFG has
six nodes and seven edges. So, the Cyclomatic complexity is V(G) = 7 - 6 + 2 = 3. It
can be verified with the other two formulae as well: # of regions + 1 = 2 + 1 = 3.
Also, # of decision points = 2. So, V(G) = 2 + 1 = 3. However, as mentioned in the
theory section, for methods of classes we add an extra 1 to the V(G). So, the
Cyclomatic complexity of this method becomes 4, which is good.
Figure 1.
CFG for "ReissueBook" method
Note that in line # 3 two decisions have been short-circuited. Taking this into
account, V(G) for the module would become 5, which is OK. This implies that the
method could have upto five linearly independent paths. By looking at figure 1 we
can easily identify three such paths. However, as mentioned that line # 3 consists
of two decision points, that results in another "implicit" path. Based on these, we
can design four test cases that would result in Boolean values for this sequence
{ user.canIssueNow, Book.IsAvailable, count < REISSUE_LIMIT }. The four such
cases are shown below:
ID transactionID = null;
Book.SetStatusIssued(bookID);
user.incrementIssueCount(bookID);
transaction.save();
transactionID = transaction.getID();
return transactionID;
ID transactionID = null;
user.incrementReissueCount(bookID);
transaction.save();
transactionID = transaction.getID();
return transactionID;