Execution Paths
The most fundamental concept in clear-box testing is the path of
execution through a program. Previously, we considered paths for
performance analysis; we are now concerned with making sure that a path
is covered and determining how to ensure that the path is in fact
executed.
We want to test the program by forcing the program to execute along
chosen paths. We force the execution of a path by giving it inputs that
cause it to take the appropriate branches. Execution of a path
exercises both the control and data aspects of the program. The control
is exercised as we take branches; both the computations leading up to
the branch decision and other computations performed along the path
exercise the data aspects.
Is it possible to execute every complete path in an arbitrary
program? The answer is no, since the program may contain a while loop
that is not guaranteed to terminate. The same is true for any program
that operates on a continuous stream of data, since we cannot
arbitrarily define the beginning and end of the data stream.
If the program always terminates, then there are indeed a finite
number of complete paths that can be enumerated from the path graph.
This leads us to the next question: Does it make sense to exercise
every path?
The answer to this question is no for most programs, since the
number of paths, especially for any program with a loop, is extremely
large. However, the choice of an appropriate subset of paths to test
requires some thought. Example 5-12
below illustrates the consequences of two different choices of
testing strategies.
Example 5-12 Choosing
the Paths to Test
Two reasonable choices for a set of paths to test follow:
- execute every statement at least once
- execute every direction of a branch at least once
These conditions are equivalent for structured programming languages
without gotos, but are not the same for unstructured code. Most
assembly language is unstructured, and state machines may be coded in
high-level languages with gotos.
To understand the difference between statement and branch coverage,
consider the CDFG below. We can execute every statement at least once
by executing the program along two distinct paths.

However, this leaves branch a out of the lower conditional
uncovered. To ensure that we have executed along every edge in the
CDFG, we must execute a third path through the program. This path does
not test any new statements, but it does cause a to be exercised.
How do we choose a set of paths that adequately covers the program's
behavior? Intuition tells us that a relatively small number of paths
should be able to cover most practical programs. Graph theory helps us
get a quantitative handle on the different paths required.
In an undirected graph, we can form any path through the graph from
combinations of basis paths. (Unfortunately, this property does not
strictly hold for directed graphs such as CDFGs, but this formulation
still helps us understand the nature of selecting a set of covering
paths through a program.) The term "basis set" comes from linear
algebra.