Unit-III Dynamic Testing Ii
Unit-III Dynamic Testing Ii
Unit-III Dynamic Testing Ii
If we want to cover every statement in the above code, then the following test cases must be
designed:
These test cases will cover every statement in the code segment, however statement coverage
is a poor criteria for logic coverage. We can see that test case 3 and 4 are sufficient to execute
all the statements in the code. But, if we execute only test case 3 and 4, then conditions and
paths in test case 1 will never be tested and errors will go undetected. Thus, statement
coverage is a necessary but not a sufficient criteria for logic coverage.
Decision or Branch Coverage
Branch coverage states that each decision takes on all possible outcomes (True or False) at
least once. In other words, each branch direction must be traversed at least once. In the
previous sample code shown in Figure 5.1, while and if statements have two outcomes: True
and False. So test cases must be designed such that both outcomes for while and if statements
are tested. The test cases are designed as:
Decision/condition Coverage
Condition coverage in a decision does not mean that the decision has been covered. If the
decision
if (A && B)
is being tested, the condition coverage would allow one to write two test cases:
Test case 1: A is True, B is False.
Test case 2: A is False, B is True.
But these test cases would not cause the THEN clause of the IF to execute (i.e. execution of
decision). The obvious way out of this dilemma is a criterion called decision/condition
coverage. It requires sufficient test cases such that each condition in a decision takes on all
possible outcomes at least once, each decision takes on all possible outcomes at least once,
and each point of entry is invoked at least once [2].
Multiple condition coverage In case of multiple conditions, even decision/ condition
coverage fails to exercise all outcomes of all conditions. The reason is that we have
considered all possible outcomes of each condition in the decision, but we have not taken all
combinations of different multiple conditions. Certain conditions mask other conditions. For
example, if an AND condition is False, none of the subsequent conditions in the expression
will be evaluated. Similarly, if an OR condition is True, none of the subsequent conditions
will be evaluated. Thus, condition coverage and decision/condition coverage need not
necessarily uncover all the errors.
Therefore, multiple condition coverage requires that we should write sufficient test cases
such that all possible combinations of condition outcomes in each decision and all points of
entry are invoked at least once. Thus, as in decision/condition coverage, all possible
combinations of multiple conditions should be considered. The following test cases can be
there:
Test case 1: A = True, B = True
Test case 2: A = True, B = False
Test case 3: A = False, B = True
Test case 4: A = False, B = False
5.3 BASIS PATH TESTING
Basis path testing is the oldest structural testing technique. The technique is based on the
control structure of the program. Based on the control structure, a fl ow graph is prepared and
all the possible paths can be covered and executed during testing. Path coverage is a more
general criterion as compared to other coverage criteria and useful for detecting more errors.
But the problem with path criteria is that programs that contain loops may have an infi nite
number of possible paths and it is not practical to test all the paths. Some criteria should be
devised such that selected paths are executed for maximum coverage of logic. Basis path
testing is the technique of selecting the paths that provide a basis set of execution paths
through the program.
The guidelines for effectiveness of path testing are discussed below:
1. Path testing is based on control structure of the program for which fl ow graph is prepared.
2. Path testing requires complete knowledge of the program’s structure.
3. Path testing is closer to the developer and used by him to test his module.
4. The effectiveness of path testing gets reduced with the increase in size of software under
test [9]. 5. Choose enough paths in a program such that maximum logic coverage is achieved.
5.3.1 CONTROL FLOW GRAPH
The control flow graph is a graphical representation of control structure of a program. F low
graphs can be prepared as a directed graph. A directed graph (V, E) consists of a set of
vertices V and a set of edges E that are ordered pairs of elements of V. Based on the concepts
of directed graph, following notations are used for a flow graph:
Node It represents one or more procedural statements. The nodes are denoted by a circle.
These are numbered or labeled.
Edges or links They represent the fl ow of control in a program. This is denoted by an arrow
on the edge. An edge must terminate at a node.
Decision node A node with more than one arrow leaving it is called a decision node.
Junction node A node with more than one arrow entering it is called a junction.
Regions Areas bounded by edges and nodes are called regions. When counting the regions,
the area outside the graph is also considered a region.
5.3.2 FLOW GRAPH NOTATIONS FOR DIFFERENT PROGRAMMING
CONSTRUCTS
Since a flow graph is prepared on the basis of control structure of a program, some
fundamental graphical notations are shown here (see Fig. 5.2) for basic programming
constructs.
Using the above notations, a flow graph can be constructed. Sequential statements having no
conditions or loops can be merged in a single node. That is why, the flow graph is also known
as decision-to-decision-graph or DD graph.
Example 5.7
5.4.4 USE OF GRAPH MATRIX FOR FINDING SET OF ALL PATHS
Another purpose of developing graph matrices is to produce a set of all paths between all
nodes. It may be of interest in path tracing to fi nd k-link paths from one node. For example,
how many 2-link paths are there from one node to another node? This process is done for
every node resulting in the set of all paths. This set can be obtained with the help of matrix
operations. The main objective is to use matrix operations to obtain the set of all paths
between all nodes. The set of all paths between all nodes is easily expressed in terms of
matrix operations.
The power operation on matrix expresses the relation between each pair of nodes via
intermediate nodes under the assumption that the relation is transitive (mostly, relations used
in testing are transitive). For example, the square of matrix represents path segments that are
2-links long. Similarly, the cube power of matrix represents path segments that are 3-links
long.
Generalizing, we can say that mth power of the matrix represents path segments that are m-
links long.
Example 5.8
Example 5.9
Consider the following graph. Derive its graph matrix and find 2-link and 3-link set of paths.
It can be generalized that for n number of nodes, we can get the set of all paths of (n − 1)
links length with the use of matrix operations. These operations can be programmed and can
be utilized as a software testing tool.
5.5 LOOP TESTING
Loop testing can be viewed as an extension to branch coverage. Loops are important in the
software from the testing viewpoint. If loops are not tested properly, bugs can go undetected.
This is the reason that loops are covered in this section exclusively. Loop testing can be done
effectively while performing development testing (unit testing by the developer) on a module.
Suffi cient test cases should be designed to test every loop thoroughly. There are four
different kinds of loops. How each kind of loop is tested, is discussed below.
Simple loops Simple loops mean, we have a single loop in the flow, as shown in Fig. 5.9.
The following test cases should be considered for simple loops while testing them [9]:
Check whether you can bypass the loop or not. If the test case for bypassing the loop
is executed and, still you enter inside the loop, it means there is a bug.
Check whether the loop control variable is negative.
Write one test case that executes the statements inside the loop.
Write test cases for a typical number of iterations through the loop.
Write test cases for checking the boundary values of the maximum and minimum
number of iterations defined (say min and max) in the loop. It means we should test
for min, min+1, min−1, max−1, max, and max+1 number of iterations through the
loop.
Nested loops
When two or more loops are embedded, it is called a nested loop, as shown in Fig. 5.10. If we
have nested loops in the program, it becomes difficult to test. If we adopt the approach of
simple tests to test the nested loops, then the number of possible test cases grows
geometrically. Thus, the strategy is to start with the innermost loops while holding outer
loops to their minimum values. Continue this outward in this manner until all loops have been
covered [9].
Concatenated loops
The loops in a program may be concatenated (Fig. 5.11). Two loops are concatenated if it is
possible to reach one after exiting the other, while still on a path from entry to exit. If the two
loops are not on the same path, then they are not concatenated. The two loops on the same
path may or may not be independent. If the loop control variable for one loop is used for
another loop, then they are concatenated, but nested loops should be treated like nested only.
Unstructured loops
This type of loops is really impractical to test and they must be redesigned or at least
converted into simple or concatenated loops.
5.6 DATA FLOW TESTING
In path coverage, the stress was to cover a path using statement or branch coverage.
However, data and data integrity is as important as code and code integrity of a module. We
have checked every possibility of the control flow of a module. But what about the dataflow
in the module? Has every data object been initialized prior to use? Have all defined data
objects been used for something? These questions can be answered if we consider data
objects in the control flow of a module.
Data flow testing is a white-box testing technique that can be used to detect improper use of
data values due to coding errors. Errors may be unintentionally introduced in a program by
programmers. For instance, a programmer might use a variable without defining it. Moreover,
he may define a variable, but not initialize it and then use that variable in a predicate.
For example, int a; if(a == 67) { }
In this way, data flow testing gives a chance to look out for inappropriate data definition, its
use in predicates, computations, and termination. It identifies potential bugs by examining the
patterns in which that piece of data is used. For example, if an out-of-scope data is being used
in a computation, then it is a bug. There may be several patterns like this which indicate data
anomalies.
To examine the patterns, the control fl ow graph of a program is used. This test strategy
selects the paths in the module’s control fl ow such that various sequences of data objects can
be chosen. The major focus is on the points at which the data receives values and the places
at which the data initialized has been referenced. Thus, we have to choose enough paths in
the control fl ow to ensure that every data is initialized before use and all the defi ned data
have been used somewhere. Data fl ow testing closely examines the state of the data in the
control fl ow graph, resulting in a richer test suite than the one obtained from control fl ow
graph based path testing strategies like branch coverage, all statement coverage, etc.
5.6.1 STATE OF A DATA OBJECT A data object can be in the following states:
Defined (d) A data object is called defined when it is initialized, i.e. when it is on the left side
of an assignment statement. Defined state can also be used to mean that a fi le has been
opened, a dynamically allocated object has been allocated, something is pushed onto the
stack, a record written, and so on [9].
Killed/Undefi ned/Released (k)
When the data has been reinitialized or the scope of a loop control variable finishes, i.e.
exiting the loop or memory is released dynamically or a fi le has been closed.
Usage (u) When the data object is on the right side of assignment or used as a control
variable in a loop, or in an expression used to evaluate the control flow of a case statement, or
as a pointer to an object, etc. In general, we say that the usage is either computational use (c-
use) or predicate use (p-use).
5.6.2 D ATA-FLOW A NOMALIES
Data-flow anomalies represent the patterns of data usage which may lead to an incorrect
execution of the code. An anomaly is denoted by a two-character sequence of actions. For
example, ‘dk’ means a variable is defined and killed without any use, which is a potential
bug. There are nine possible two-character combinations out of which only four are data
anomalies, as shown in Table 5.1.
5.6.3 TERMINOLOGY USED IN DATA FLOW TESTING
In this section, some terminology [9, 20], which will help in understanding all the concepts
related to dataflow testing, is being discussed. Suppose P is a program that has a graph G(P)
and a set of variables V. The graph has a single entry and exit node.
Definition node Defining a variable means assigning value to a variable for the very fi rst
time in a program. For example, input statements, assignment statements, loop control
statements, procedure calls, etc.
Usage node It means the variable has been used in some statement of the program. Node n
that belongs to G(P) is a usage node of variable v, if the value of variable v is used at the
statement corresponding to node n. For example, output statements, assignment statements
(right), conditional statements, loop control statements, etc.
A usage node can be of the following two types:
(i) Predicate U sage Node: If usage node n is a predicate node, then n is a predicate
usage node.
(ii) Computation Usage Node: If usage node n corresponds to a computation
statement in a program other than predicate, then it is called a computation usage
node.
Loop-free path segment It is a path segment for which every node is visited once at
most. Simple path segment It is a path segment in which at most one node is visited
twice. A simple path segment is either loop-free or if there is a loop, only one node is
involved.
Definition-use path (du-path) A du-path with respect to a variable v is a path between
the definition node and the usage node of that variable. Usage node can either be a p-
usage or a c-usage node.
Definition-clear path(dc-path)
A dc-path with respect to a variable v is a path between the definition node and the usage
node such that no other node in the path is a defining node of variable v.
The du-paths which are not dc-paths are important from testing viewpoint, as these are
potential problematic spots for testing persons. Those du-paths which are definition-clear
are easy to test in comparison to du-paths which are not dc-paths. The application of data
flow testing can be extended to debugging where a testing person finds the problematic
areas in code to trace the bug. So the du-paths which are not dc-paths need more
attention.
Project management
A project needs monitoring and control. It depends on some data obtained from the
development team. However, this data cannot be relied on forever. Inspection is another
effective tool for monitoring the progress of the project.
Checking coupling and cohesion
The modules’ coupling and cohesion can be checked easily through inspection as
compared to dynamic testing. This also reduces the maintenance work.
Learning through inspection
Inspection also improves the capability of different team members, as they learn from the
discussions on various types of bugs and the reasons why they occur. It may be more
benefi cial for new members. They can learn about the project in a very short time. This
helps them in the later stages of development and testing.
Process improvement
There is always scope of learning from the results of one process. An analysis of why the
errors occurred or the frequent places where the errors occurred can be done by the
inspection team members. The analysis results can then be used to improve the inspection
process so that the current as well as future projects can benefi t. Discussed below are the
issues of process improvement.
Finding most error-prone modules
Through the inspection process, the modules can be analysed based on the error-density
of the individual module, as shown in Table 6.1.
assumes that the inspection itself takes about an hour and that each member spends 1-2
hours preparing for the inspection. Testing costs are variable and depend on the number
of faults in the software. However, the effort required for the program inspection is less
than half the effort that would be required for equivalent dynamic testing. Further, it has
been estimated that the cost of inspection can be 5–10% of the total cost of the project.
6.1.6 VARIANTS OF INSPECTION PROCESS
After Fagan’s original formal inspection concept, many researchers proposed
modifications in it. Table 6.3 lists some of the variants of the formal inspection.
Formal Technical Asynchronous Review Method ( FTArm)
In this process, the meeting phase of inspection is considered expensive and therefore,
the idea is to eliminate this phase. The inspection process is carried out without having a
meeting of the members. This is a type of asynchronous inspection [88] in which the
inspectors never have to simultaneously meet. For this process, an online version of the
document is made available to every member where they can add their comments and
point out the bugs. This process consists of the following steps, as shown in Fig. 6.3.
Setup It involves choosing the members and preparing the document for an asynchronous
inspection process. The document is prepared as a hypertext document.
Consolidation In this step, the moderator analyses the result of private and public
reviews and lists the findings and unresolved issues, if any.
Group meeting If required, any unresolved issues are discussed in this step. But the
decision to conduct a group meeting is taken in the previous step only by the moderator.
Conclusion The final report of the inspection process along with the analysis is produced
by the moderator.
Gilb Inspection
Gilb and Graham [89] defi ned this process. It differs from Fagan inspection in that the
defect detection is carried out by individual inspectors at their own level rather than in a
group. Therefore, a checking phase has been introduced.
Three different roles are defi ned in this type of inspection:
Leader is responsible for planning and running the inspection.
Author of the document
Checker is responsible for finding and reporting the defects in the document. The
inspection process consists of the following steps, as shown in Fig. 6.4.
The moderator may also prepare a checklist to help the team focus on the key points. The
result of the review should be a document recording the events of the meeting,
deficiencies identified, and review team recommendations. Appropriate actions should
then be taken to correct any deficiencies and address all recommendations.