Thanks to visit codestin.com
Credit goes to www.scribd.com

0% found this document useful (0 votes)
8 views21 pages

Module 3 Final 2

The document discusses the importance of graph coverage in software testing, particularly in object-oriented (OO) software design, emphasizing the complexity of testing design relationships due to modularity and reuse. It highlights the use of call graphs for structural design testing and the challenges of applying node and edge coverage in class call graphs. Additionally, it explores data flow analysis, inter-procedural def-use pairs, and the complexities introduced by inheritance, polymorphism, and dynamic binding in testing OO software and web applications.

Uploaded by

Karnnan Bv
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views21 pages

Module 3 Final 2

The document discusses the importance of graph coverage in software testing, particularly in object-oriented (OO) software design, emphasizing the complexity of testing design relationships due to modularity and reuse. It highlights the use of call graphs for structural design testing and the challenges of applying node and edge coverage in class call graphs. Additionally, it explores data flow analysis, inter-procedural def-use pairs, and the complexities introduced by inheritance, polymorphism, and dynamic binding in testing OO software and web applications.

Uploaded by

Karnnan Bv
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

Introduction to Software Testing

Graph Coverage for Design


Elements
OO Software and Designs
• Emphasis on modularity and reuse puts complexity in the
design connections

• Testing design relationships is more important than before

• Graphs are based on the connections among the software


components
• Connections are dependency relations, also called couplings

I
Call Graph
• The most common graph for structural design testing
• Nodes : Units (in Java – methods)
• Edges : Calls to units

A Node coverage : call every unit at least once


(method coverage)
B C D

E F Edge coverage : execute every call at least


once (call coverage)
Example call graph

I
Call Graphs on Classes
• Node and edge coverage of class call graphs often do not work very well
• Individual methods might not call each other at all!

Class stack
public void push (Object o)
public Object pop ( ) ???
public boolean isEmpty (Object o)

push pop isEmpty

Other types of testing are needed – do not use graph criteria

I
Inheritance & Polymorphism
Caution : Ideas are preliminary and not widely used
A
Classes are not executable, so
this graph is not directly testable
B
We need objects

C D A
a
Example inheritance
hierarchy graph B objects
b

C D What is coverage
c d on this graph ?

I
Coverage on Inheritance Graph
• Create an object for each class ?
• This seems weak because there is no execution

• Create an object for each class and apply call coverage?

OO Call Coverage : TR contains each reachable node in the call


graph of an object instantiated for each class in the class
hierarchy.

OO Object Call Coverage : TR contains each reachable node in


the call graph of every object instantiated for each class in the
class hierarchy.

• Data flow is probably more appropriate …


I
Data Flow at the Design Level
• Data flow couplings among units and classes are more complicated than
control flow couplings
• When values are passed, they “change names”
• Many different ways to share data
• Finding defs and uses can be difficult – finding which uses a def can reach is very
difficult
• When software gets complicated … testers should get interested
• That’s where the faults are!

• Caller : A unit that invokes another unit


• Callee : The unit that is called
• Callsite : Statement or node where the call appears
• Actual parameter : Variable in the caller
• Formal parameter : Variable in the callee

I
Example Call Site
A Caller

B (x) Actual
 Parameter
interface end A
Callee
B (Y)
 Formal
Parameter
end B
• Applying data flow criteria to def-use pairs between units is too expensive
• Too many possibilities
• But this is integration testing, and we really only care about the interface …

I
Inter-procedural DU Pairs

• If we focus on the interface, then we just need to consider the last


definitions of variables before calls and returns and first uses inside
units and after calls

• Last-def : The set of nodes that define a variable x and has a def-clear
path from the node through a callsite to a use in the other unit
• Can be from caller to callee (parameter or shared variable) or from callee to
caller as a return value

• First-use : The set of nodes that have uses of a variable y and for
which there is a def-clear and use-clear path from the callsite to the
nodes

I
Example Inter-procedural DU Pairs
Caller
1 x=5
F X = 14 last-def
 10 B (int y)
y = G (x) callsite 2 x=4
DU pair 
print (y) 11 Z = y 12 T = y
first-use 3 x=3

Callee 13 print (y)


4 B (x)
G (a) print (a)
first-use
DU  Last Defs
pair b = 42 2, 3
last-def

return (b) First Uses
11, 12

I
Example – Quadratic
25 ok = Root (X, Y, Z);
1 // Program to compute the quadratic root for 26 if (ok)
two numbers 27 System.out.println
2 import java.lang.Math; 28 (“Quadratic: ” + Root1 + Root2);
3 29 else
4 class Quadratic 30 System.out.println (“No Solution.”);
5{ 31 }
6 private static float Root1, Root2; 32
7 33 // Three positive integers, finds quadratic root
8 public static void main (String[] argv) 34 private static boolean Root (int A, int B, int C)
9 { 35 {
10 int X, Y, Z; 36 float D;
11 boolean ok; 37 boolean Result;
12 int controlFlag = Integer.parseInt (argv[0]); 38 D = (float) Math.pow ((double)B,
13 if (controlFlag == 1) (double2-4.0)*A*C );
14 { 39 if (D < 0.0)
15 X = Integer.parseInt (argv[1]); 40 {
16 Y = Integer.parseInt (argv[2]); 41 Result = false;
17 Z = Integer.parseInt (argv[3]);
18 } 42 return (Result);
19 else 43 }
20 { 44 Root1 = (float) ((-B + Math.sqrt(D))/(2.0*A));
45 Root2 = (float) ((-B – Math.sqrt(D))/(2.0*A));
21 X = 10; 46 Result = true;
22 Y = 9; 47 return (Result);
23 Z = 12; 48 } / /End method Root
24 } 49
I 50 } // End class Quadratic
1 // Program to compute the quadratic root for two numbers
2 import java.lang.Math;
3
4 class Quadratic
5{
6 private static float Root1, Root2; shared variables
7
8 public static void main (String[] argv)
9 {
10 int X, Y, Z;
11 boolean ok;
12 int controlFlag = Integer.parseInt (argv[0]);
13 if (controlFlag == 1)
14 {
15 X = Integer.parseInt (argv[1]);
last-defs 16 Y = Integer.parseInt (argv[2]);
17 Z = Integer.parseInt (argv[3]);
18 }
19 else
20 {
21 X = 10;
22 Y = 9;
23 Z = 12;
24 }
I
25 ok = Root (X, Y, Z);
first-use 26 if (ok)
27 System.out.println
28 (“Quadratic: ” + Root1 + Root2);
29 else
30 System.out.println (“No Solution.”);
31 }
32
33 // Three positive integers, finds the quadratic root
34 private static boolean Root (int A, int B, int C)
first-use 35 {
36 float D;
37 boolean Result;
38 D = (float) Math.pow ((double)B, (double2-4.0)*A*C);
39 if (D < 0.0)
40 {
last-def 41 Result = false;
42 return (Result);
43 }
44 Root1 = (float) ((-B + Math.sqrt(D)) / (2.0*A));
last-defs 45 Root2 = (float) ((-B – Math.sqrt(D)) / (2.0*A));
46 Result = true;
47 return (Result);
48 } / /End method Root
49
50 } // End class Quadratic
I
Quadratic – Coupling DU-pairs

Pairs of locations: method name, variable name, statement


(main (), X, 15) – (Root (), A, 38)
(main (), Y, 16) – (Root (), B, 38)
(main (), Z, 17) – (Root (), C, 38)
(main (), X, 21) – (Root (), A, 38)
(main (), Y, 22) – (Root (), B, 38)
(main (), Z, 23) – (Root (), C, 38)
(Root (), Root1, 44) – (main (), Root1, 28)
(Root (), Root2, 45) – (main (), Root2, 28)
(Root (), Result, 41) – ( main (), ok, 26 )
(Root (), Result, 46) – ( main (), ok, 26 )

I
Coupling Data Flow Notes
• Only variables that are used or defined in the callee

• Implicit initializations of class and global variables

• Transitive DU-pairs are too expensive to handle


– A calls B, B calls C, and there is a variable defined in A and used in C

• Arrays : a reference to one element is considered to be


a reference to all elements

I
Inheritance, Polymorphism & Dynamic Binding

• Additional control and data connections make data flow analysis more
complex

• The defining and using units may be in different call hierarchies

• When inheritance hierarchies are used, a def in one unit could


reach uses in any class in the inheritance hierarchy

• With dynamic binding, the same location can reach different


uses depending on the current type of the using object

• The same location can have different definitions or uses at


different points in the execution !

I
Additional Definitions
• Inheritance : If class B inherits from class A, then all variables and methods in
A are implicitly in B, and B can add more
• A is the parent or ancestor
• B is the child or descendent

• An object reference obj that is declared to be of type A can be assigned an


object of either type A, B, or any of B’s descendents
• Declared type : The type used in the declaration: A obj;
• Actual type : The type used in the object assignment: obj = new B();

• Class (State) Variables : The variables declared at the class level, often private

I
Types of Def-Use Pairs
def
def last-def
A () A ()
use
inter-procedural
B () first-use data flow
A () use B ()
intra-procedural data flow
(within the same unit) full coupling

def
A() M () A() def
A()
M() A()

B() use N()


B() use
B()
N() B()
F () F()

object-oriented direct object-oriented indirect


I
coupling data flow coupling data flow
OO Data Flow Summary

• The defs and uses could be in the same class, or


different classes

• Researchers have applied data flow testing to the


direct coupling OO situation
• Has not been used in practice
• No tools available

• Indirect coupling data flow testing has not been tried


either in research or in practice
• Analysis cost may be prohibitive

I
Web Applications and Other Distributed Software

P1 message P2

def use
A() B()

distributed software data flow

• “message” could be HTTP, RMI, or other mechanism


• A() and B() could be in the same class or accessing a
persistent variable such as in a web session
• Beyond current technologies

I
Summary—What Works?

• Call graphs are common and very useful ways to


design integration tests
• Inter-procedural data flow is relatively easy to
compute and results in effective integration tests
• The ideas for OO software and web applications are
preliminary and have not been used much in
practice

You might also like