You are on page 1of 106

Speci cation and Veri cation of Object-Oriented Programs

Shekhar Kirani1 and W. T. Tsai


Computer Science Department
University of Minnesota
Minneapolis, MN 55455
fshekar,tsaig@cs.umn.edu

December 4, 1994

1
Currently employed at U S WEST Technologies, Boulder, CO. kirani@advtech.uswest.com
Abstract
There is an increasing demand for innovative software that satisfy stringent quality and reliability re-
quirements imposed by users. In recent years Object-Oriented (OO) paradigm is gaining acceptance
for developing complex software. The current research so far in OO software engineering is focussed
on problem analysis, software design and implementation techniques resulting in a potpourri of rep-
resentations and procedures. Even though the importance of Veri cation and Validation (V&V) is
known, it has commanded little attention in OO paradigm.
In this thesis1 we propose a new speci cation technique called Method and Message Sequence
Speci cation that represents the causal relationship between the instance methods of a set of classes.
The Method Sequence Speci cation (MtSS) of a class documents the correct causal order in which
the methods can be invoked at an instance of the class. The Message Sequence Speci cation (MgSS)
of a set of classes documents the causal order in which messages can be sent to instances of di er-
ent classes. MtSS and MgSS of classes document the message-method interaction and the correct
sequence in which messages can ow through a system containing objects.
The importance of speci cation Consistency and Completeness (C&C) is well known in software
engineering. Inconsistency and incompleteness in MtSS and MgSS would lead to faulty design and
therefore, C&C of class speci cation is essential for developing OO design with less faults. In this
thesis, we provide a set of rules for developing consistent MtSS and MgSS for both single classes and
a set of classes. We also discuss about run time veri cation system that can ensure that each object
is compliant with the corresponding MtSS. The implementation of a OO design must comply with
the design. We propose a new technique of data anomaly detection in OO implementation using
MtSS. We then propose several test case generation techniques using MtSS and MgSS that can be
used for testing the OO implementation. We also present the results of applying various testing
techniques against an example OO program.

1 This technical report is a short version of the doctoral thesis by Dr. Kirani [40].

i
Contents
1 Introduction 1
1.1 Object-Oriented Concepts : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 4
1.1.1 Object (Class Instances) : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 4
1.1.2 Class : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 4
1.1.3 Inheritance : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 5
1.1.4 OO Software Development Life-Cycle : : : : : : : : : : : : : : : : : : : : : : 5
1.1.5 OO Potential Bene ts and Drawbacks : : : : : : : : : : : : : : : : : : : : : : 6
1.2 Testing Concepts : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 6
1.2.1 What is Testing? : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 7
1.2.2 Why Testing is Hard? : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 7
1.2.3 Generation of Expected Output is Dicult : : : : : : : : : : : : : : : : : : : 10
1.2.4 Testing Techniques : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 11
1.3 Related Research in OO Testing : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 13
2 Method and Message Sequence Speci cation 15
2.1 Method Sequence Speci cation (MtSS) : : : : : : : : : : : : : : : : : : : : : : : : : : 16
2.1.1 Properties satis ed by MtSS : : : : : : : : : : : : : : : : : : : : : : : : : : : 18
2.2 MtSS Derivation from Design : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 19
2.2.1 MtSS from State Transition Diagram : : : : : : : : : : : : : : : : : : : : : : : 19
2.2.2 MtSS from Object Diagram : : : : : : : : : : : : : : : : : : : : : : : : : : : : 20
2.3 Message Sequence Speci cation (MgSS) : : : : : : : : : : : : : : : : : : : : : : : : : 22
2.3.1 MgSS and MtSS from Interaction Diagram : : : : : : : : : : : : : : : : : : : 24
3 Consistency and Completeness of MtSS and MgSS 27
3.1 Inheritance and C&C of MtSS : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 28
3.1.1 Specialization Inheritance and MtSS : : : : : : : : : : : : : : : : : : : : : : : 29
3.1.2 Re nement Inheritance and MtSS : : : : : : : : : : : : : : : : : : : : : : : : 30
3.1.3 Inheritance for Implementation and MtSS : : : : : : : : : : : : : : : : : : : : 31
3.1.4 Feasibility Evaluation : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 32
3.2 Multiple Interfaces and MtSS : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 33
3.2.1 C&C of MtSS with Multiple Interfaces : : : : : : : : : : : : : : : : : : : : : : 34
3.3 Algorithm for Consistency Checking : : : : : : : : : : : : : : : : : : : : : : : : : : : 34
3.4 C&C of MgSS : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 35

ii
4 C&C of Implementation 37
4.1 Run-time Veri cation System : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 38
5 Data Flow Anomaly Detection in Classes 41
5.1 Introduction : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 41
5.1.1 Related Research : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 42
5.2 Data ow Anomalies : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 42
5.2.1 Data ow Anomaly Model : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 43
5.2.2 Anomaly Detection in Conventional Programs : : : : : : : : : : : : : : : : : 44
5.3 Data Flow Anomaly in Classes : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 46
5.3.1 Data Flow Anomaly Detection in Classes : : : : : : : : : : : : : : : : : : : : 48
5.4 Inheritance and Data Flow Anomalies : : : : : : : : : : : : : : : : : : : : : : : : : : 52
5.4.1 Specialization Inheritance and Anomaly Detection : : : : : : : : : : : : : : : 53
5.4.2 Re nement Inheritance and Anomaly Detection : : : : : : : : : : : : : : : : : 55
5.4.3 Implementation Inheritance and Anomaly Detection : : : : : : : : : : : : : : 56
5.5 Conclusion : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 56
6 Test Case Generation from Speci cation 57
6.1 Introduction to Test Case Generation : : : : : : : : : : : : : : : : : : : : : : : : : : 58
6.1.1 Identi cation of Components and Interactions : : : : : : : : : : : : : : : : : : 58
6.1.2 Test Input and Expected Output Generation : : : : : : : : : : : : : : : : : : 59
6.2 Test Case Generation for Methods : : : : : : : : : : : : : : : : : : : : : : : : : : : : 59
6.2.1 Application of Procedural Testing Techniques : : : : : : : : : : : : : : : : : : 59
6.2.2 Inheritance and Test Case Generation : : : : : : : : : : : : : : : : : : : : : : 60
6.3 Test Case Generation : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 60
6.4 Test Case Generation From Single Class : : : : : : : : : : : : : : : : : : : : : : : : : 61
6.4.1 Single Class Random Test Cases : : : : : : : : : : : : : : : : : : : : : : : : : 61
6.4.2 Single Class Partition Test Cases : : : : : : : : : : : : : : : : : : : : : : : : : 64
6.4.3 Single Class Data Flow Test Cases : : : : : : : : : : : : : : : : : : : : : : : : 68
6.5 Inter Class Test Case Generation : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 70
6.5.1 Test Cases from Method Interactions : : : : : : : : : : : : : : : : : : : : : : : 72
6.5.2 Multiple Class Data Flow Test Cases : : : : : : : : : : : : : : : : : : : : : : : 74
6.5.3 Multiple Class Random Test Cases : : : : : : : : : : : : : : : : : : : : : : : : 75
6.5.4 Multiple Class Partition Test Cases : : : : : : : : : : : : : : : : : : : : : : : 77
6.5.5 Scenario Based Test Sequence Generation : : : : : : : : : : : : : : : : : : : : 77
6.6 Test Case Generation from State Transition Diagram : : : : : : : : : : : : : : : : : : 78
6.6.1 All State Coverage Method Sequences : : : : : : : : : : : : : : : : : : : : : : 80
6.6.2 All Method Coverage Sequences : : : : : : : : : : : : : : : : : : : : : : : : : 80
6.7 Test Case Generation for Robustness : : : : : : : : : : : : : : : : : : : : : : : : : : : 81
6.7.1 Negative Test Sequences from MtSS : : : : : : : : : : : : : : : : : : : : : : : 81
6.7.2 Negative Test Sequences from MgSS : : : : : : : : : : : : : : : : : : : : : : : 82

iii
7 Application of OO Testing Techniques 85
7.1 Class Metrics : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 85
7.2 Test Case Execution Order : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 87
7.3 Test Case Execution Results : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 87
7.4 Summary : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 89
8 Conclusion 90
8.1 Research Directions : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 92

iv
List of Figures
1.1 Clusters of objects interacting with each other: Objects at Run Time : :::::::: 2
1.2 Veri cation and Validation of OO Software: Thesis Concentration : : :::::::: 3
1.3 Concurrent development of classes in OO paradigm : : : : : : : : : : :::::::: 5
1.4 The conventional software development paradigm : : : : : : : : : : : : :::::::: 7
2.1 Account Class attributes and methods : : : : : : : : : : : : : : : : : : : : : : : : : : 18
2.2 STD corresponding to Account Class : : : : : : : : : : : : : : : : : : : : : : : : : : : 20
2.3 Object Diagram for Account Class : : : : : : : : : : : : : : : : : : : : : : : : : : : : 22
2.4 Diagram for illustrating MgSS : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 23
2.5 Deriving MgSS from Interaction Diagram: Example : : : : : : : : : : : : : : : : : : 25
3.1 Example Illustrating Re nement Inheritance : : : : : : : : : : : : : : : : : : : : : : 31
3.2 Speci cation and Veri cation of Counter Design : : : : : : : : : : : : : : : : : : : : : 32
3.3 Example Illustrating Multiple Interfaces of Account Class : : : : : : : : : : : : : : : 35
4.1 An example for illustrating veri cation of implementation against the speci cation. : 38
4.2 Data structure diagram for implementing run-time veri cation system : : : : : : : : 39
5.1 Example to illustrate the data ow anomaly model and detection : : : : : : : : : : : 43
5.2 Flow graph corresponding to the example given in gure 5.1 : : : : : : : : : : : : : : 45
5.3 Regular Expression to Control Flow Graph Conversion. : : : : : : : : : : : : : : : : 49
5.4 Control Flow Graph representation of the sequence speci cation of \Account" Class. 51
5.5 Partial inheritance hierarchy for SequenceableCollection class in Smalltalk : : : : : : 53
5.6 Example for Specialization Inheritance with two new methods : : : : : : : : : : : : : 54
6.1 Account Class Example for generating test cases : : : : : : : : : : : : : : : : : : : : 62
6.2 Class Interaction Diagram for ATM Design: Part1 : : : : : : : : : : : : : : : : : : : 71
6.3 Class Interaction Diagram for ATM Design: Part2 : : : : : : : : : : : : : : : : : : : 72
6.4 State Transition Diagram for the Account Class : : : : : : : : : : : : : : : : : : : : : 79

v
List of Tables
1.1 Sizes of possible input and output spaces (from Buchanan-88) : : : : : : : : : : : : : 9
1.2 Diculties in generating test inputs. : : : : : : : : : : : : : : : : : : : : : : : : : : : 9
1.3 Diculties in generating expected test outputs : : : : : : : : : : : : : : : : : : : : : 10
6.1 Summary of Testing Techniques discussed in this chapter : : : : : : : : : : : : : : : 61
6.2 Example of random test case with test inputs and expected outputs. : : : : : : : : : 63
6.3 Category based partitioning of the Account class methods : : : : : : : : : : : : : : : 66
7.1 Number of methods in each class under each category of methods : : : : : : : : : : : 86
7.2 Average size of methods in each class under each category of methods : : : : : : : : 86
7.3 Fault density for in each class under each category of methods : : : : : : : : : : : : 86
7.4 Number of test cases generated for each testing technique for classes : : : : : : : : : 87
7.5 Categories of faults that were recognized during testing : : : : : : : : : : : : : : : : 88
7.6 Faults found by Random testing technique : : : : : : : : : : : : : : : : : : : : : : : : 88
7.7 Faults found by Partition testing technique : : : : : : : : : : : : : : : : : : : : : : : 88

vi
Chapter 1

Introduction
There is an increasing demand for innovative software that satisfy stringent quality and reliability re-
quirements imposed by users. In recent years Object-Oriented (OO) paradigm is gaining acceptance
for developing software for complex applications. OO paradigm has moved into mainstream software
development industry. It is currently being used in variety of applications development starting from
system software such as databases, operating systems to application software for banking, billing,
service providing and so on [12, 66].
Software is inherently complex and this complexity of the software is its fundamental property,
not an accidental one. The complexity is due to diculty in comprehending the problem domain
completely, the exibility in software and diculty in managing development process [13]. OO
software development is based on identifying and modeling the real-world entities as objects. OO
paradigm supports abstraction, decomposition, encapsulation, modularity, and hierarchy. Thus
OO-based software engineering is seen as an approach for tackling the intricacies and complexities
associated with software construction [51, 12, 47].
The current research so far in OO software engineering is focussed on problem analysis, software
design, and implementation techniques resulting in a potpourri of representations and procedures
[51, 12, 18, 19, 47, 54]. OO analysis methods help in identifying and expressing software requirements
in the vocabulary of classes and objects found in the problem domain. OO design methods facilitate
in identifying the relationship among objects and help in depicting both static and dynamic models
as well as logical and physical models of the system. During design, many of the objects and classes
identi ed during analysis are retained and are re ned. During OO implementation, each of the
classes and objects that were designed are constructed in such a way that they conform to the static
and dynamic models built during design.
It has been studied that Veri cation and Validation (V&V) related activities consume at least half
of the labor to bring out a production quality software [9, 78]. In conventional paradigm, statistics
show that a software programmed well will still have one to three bugs per hundred statements [75].
This quality of the software is not acceptable in many critical applications such as nuclear reactor
control [58], or safety critical systems [53]. Even though the importance of (V&V) is well known, it
has commanded little attention in OO paradigm. A sound software engineering practice is to verify
and validate everything that is developed. Thus, extensive V&V during software development is
essential for building zero-defect software [21]. Unfortunately, most of the OO analysis and design
techniques proposed to date do not adequately address V&V activities. Currently, most of the V&V

1
objects

start

object clusters

Figure 1.1: Clusters of objects interacting with each other: Objects at Run Time

activities are ad-hoc. If successful V&V techniques for OO paradigm are not developed, there is a
great risk of failure of OO paradigm as a next-generation software development technique.
An OO application consists of a set of class instances interacting with one another by sending
messages and invoking methods. In gure 1.1, an object diagram consisting of a set of run time
objects is shown. An application usually consists of clusters of objects such as the objects related
to user-interfaces and objects related to databases. Within each cluster, objects send messages to
each other to perform tasks. Across all the objects there is little or no global data. Both the data,
and the operations performed on the data are encapsulated inside the objects. The objects store the
state internally and communicate with other objects only through messages. Thus, the fundamental
units of program in OO software are classes and objects. A set of objects accomplish the required
task of the application by sending sequence of messages through the object space.
The sequence in which each object invokes its method is important for the proper functioning
of the object. In this thesis, we propose a new speci cation technique called Method and Message
Sequence Speci cation that represents the causal relationship between the instance methods of a set
of classes. The Method Sequence Speci cation (MtSS) of a class documents the correct causal order
in which the methods of the class can be invoked. The Message Sequence Speci cation (MgSS) of
a set of classes documents the causal order in which messages can be sent out to di erent instances
of classes by a method. MtSS and MgSS of classes document the message-method interaction and
the correct sequence in which messages can ow through a system of objects. The primary goal
of MtSS and MgSS is to facilitate the V&V of classes. The MtSS and MgSS can be derived from
OO analysis and design products (see gure 1.2). In this thesis we usually refer MtSS and MgSS
together as sequence speci cation.
In this thesis, we discuss the technique of deriving MtSS of classes from the products of analysis
and design (refer gure 1.2). The MtSS and MgSS of a class is not a complete speci cation of the

2
OO Analysis

OO Specification
Internal C&C

OO Design External C&C

OO Source Code
OO
Implementation
Thesis Concentration

Figure 1.2: Veri cation and Validation of OO Software: Thesis Concentration

class, but captures only those features that are necessary for V&V. The MtSS and MgSS represents
the method interactions, i.e. the dynamic interactions between the class instances. The MtSS and
MgSS can be easily incorporated as a part of many OO analysis and design techniques to capture
the sequence speci cation. It is also possible to derive the sequence speci cation from OO analysis
and design products. We rst discuss a technique of deriving MtSS of a class from the corresponding
state based OO design. We then discuss the derivation of MtSS and MgSS from other well-known
dynamic models built during design such as object diagram[12], event trace diagram[66], or use-case
diagrams [37].
The importance of speci cation Consistency and Completeness (C&C) is well-known in software
engineering. Inconsistency and incompleteness in sequence speci cation would lead to faulty ver-
i cation and therefore, C&C of the speci cation is essential for developing OO systems with less
faults. Since MtSS and MgSS is derived using the analysis and design products of the OO system,
inconsistency and incompleteness identi ed in MtSS and MgSS can be re ected back to the analy-
sis and design products. Thus, C&C of MtSS and MgSS help in identifying faults in the analysis
and design. In this thesis, we provide rules for checking the consistency of MtSS and MgSS in the
presence of single and multiple inheritance. We then extend the rules to check the consistency and
completeness in the presence of multiple interfaces to a class.
An implementation of a OO design must comply with the design. Since implementation from
design is a manual process, several faults can be introduced in OO implementation. In this thesis,
we propose several testing techniques to identify faults in the implementation. We propose both
static and dynamic testing techniques. The data ow anomaly testing is the static testing method
that uses the MtSS and OO source program of an implementation to identify data ow anomalies
in the implementation. The dynamic testing techniques include random, partition, data ow, and
scenario based testing. We discuss about generating test cases from single class, several classes, and

3
state-transition diagram of the class instances. An implementation of a design might not completely
comply with the MtSS of the class. Further, testing of an implementation might not reveal all the
out-of-sequence messages to instances of a class. In this thesis, we propose a run-time veri cation
system that checks for the consistency of messages received at each object with respect to its sequence
speci cation and ags out out-of-sequence messages. A support for run-time veri cation is very
essential in safety-critical systems[53].
Research in V&V of OO systems will continue to introduce new testing techniques for OO
systems. These testing techniques vary in their e ectiveness, robustness, and cost. In this thesis,
we propose a testing technique evaluation methodology based on life cycle mutation testing. This
evaluation scheme facilitates the evaluation of various testing techniques. The life cycle mutation
testing is independent of a development paradigm. This evaluation methodology has been used and
evaluated with respect to several of the above testing techniques in the context of expert system
testing and is found to be e ective.
In the rest of this chapter we discuss about OO as well as V&V related concepts.

1.1 Object-Oriented Concepts


In OO model, the fundamental entities are objects compared to procedures and functions in im-
perative programming languages. Objects send messages to other objects, execute a method when
a message is received from other object, and maintain an encapsulated local state. In an object-
oriented program a functionality is implemented by sending and receiving messages between objects.
In this section, we review the concept of objects, interaction between objects, classes, and inheri-
tance.
1.1.1 Object (Class Instances)
An object encomposes state and behavior. The state of an object is determined by a set of attributes
and their values. The behavior of an object is de ned by a set of methods (operations) of the object.
Methods are an abstraction of procedures and functions. An object encapsulates its state and only
the methods of the object can refer or modify the state of the object.
Messages are requests sent from one object to other for computing a desired functionality. Meth-
ods are the functions an object executes in response to a message. There exists a one-to-one relation
between the messages an object receives and the method it executes [76]. A method before sending
a message to other object, must uniquely identify the other object. In addition, an object accessing
the services of other objects must know the proper interface protocol of the objects. The instance
methods of a class can be classi ed into de ne, use, or de ne-use type. The de ne type methods
change object state by modifying the attribute contents. The use type methods (also known as
implementor methods) access the current values of attributes. The de ne-use type method uses as
well as changes the contents of attributes[45]. The objects in a system are created during execution
time.
1.1.2 Class
Classes describe a common behavior of a group of unique objects. A class is a static description
of a set of objects. A class describes all the instance methods and attributes. During execution,

4
Object, class, and structure
Identification

Individual
classes
OOA OOA

OOT OOT

OOP OOD OOP OOD


Figure 1.3: Concurrent development of classes in OO paradigm

objects are created by instantiating classes. A class provides abstraction by providing an interface
and encapsulating its internal structure.
Each class instantiates objects based on a message it receives to create a new object. Each object
thus created from a class receives messages from methods in other objects. Thus, each object in its
life-time gets di erent sets of messages. Even though a class de nes several methods, some of its
objects may not execute all the methods it supports.
1.1.3 Inheritance
Inheritance models hierarchical relationship between classes. It is used for expressing specialization.
In inheritance, a child class inherits methods and attributes of a parent class. An inherited property
may be rede ned by a subclass, nullifying the inherited de nition. This feature in inheritance
encourages the reuse of code written for parent classes. In single inheritance a child class inherits
from a single parent class and in multiple inheritance a child class inherits from more than one
parent class.
1.1.4 OO Software Development Life-Cycle
OO paradigm promotes concurrency in software development life-cycle phases. Unlike conventional
techniques, in OO software life-cycle, several classes can be concurrently analyzed, designed, im-
plemented, and tested. Concurrent development of individual and related classes facilitate better
understanding of requirements, alleviates risk, and thus help in dividing the complexity of a prob-
lem. It also helps in producing early tangible results [17]. In gure 1.3 several threads of software
development activities are shown. Each thread corresponds to the development of a class and usually
there exists a dependency relation across the threads.
OO analysis is a process of expressing the requirements in terms of classes and objects found
in the problem domain. OO design is a process of identifying the structure and decomposition of

5
classes, and depiction of logical as well as physical models of object and class interaction. Even
though in OO paradigm it is possible to concurrently perform analysis, design and implementation
of classes, each class is developed sequentially [17]. Early C&C of designed classes help in the
detection of contradictions and gaps and thus promote reliable implementation.
1.1.5 OO Potential Bene ts and Drawbacks
From the software engineering life-cycle perspective, it is advocated to design systems that are mod-
ular and well encapsulated. It is often preferred to design a system that abstracts and mimics the
actual problem domain. Further, a design must be done with divide-and-conquer principle. In ad-
dition, explicit traceability between analysis and design products are essential during maintenance.
The OO paradigm supports most of the above principles in its notation and thus facilitates de-
velopment of modular and well-encapsulated applications. In OO paradigm, the problem domain
objects are re ned in design and are then implemented providing an explicit traceability. The lan-
guages used for implementing OO based applications support most of the above principles and foster
development of complex reusable applications.
The OO paradigm is new and most of the design techniques are not still engineered as a stable and
reliable method for software development. The basic mode of functioning in OO based application is
by message passing. As each of the method performs very little, most of the work is done by various
method executions contained in di erent objects. Further, the state of the application is distributed
and encapsulated in di erent objects. Thus, to get a proper understanding, testing, and debugging
of the system, tracing of the methods and messages is essential.

1.2 Testing Concepts


It has been reported that to bring out a production quality software, testing related activities
consume at least half of the labor[9, 78]. The primary goal of software testing is to ensure that the
end product under investigation is in conformance with the product from which the end product
was built. In this section, we introduce various concepts in testing and discuss with respect to OO
paradigm.
In this paper we adopt the IEEE standard terminology of error, fault, and failure. According
to this terminology errors represent human mistakes which can result in faults in a system. The
execution of a faulty system produces failures [56]. A fault (or commonly referred to as bug) may
cause a system to fail on multiple inputs, but each failure can potentially lead to the discovery of a
new fault. Thus, multiple failures of a system do not necessarily imply that the system has multiple
faults. The purpose of testing is to nd faults in system, thus we are interested in nding minimum
number of test cases that can produce maximum number of failures in the concerned system to
achieve a desired level of reliability.
Veri cation and Validation are commonly used for testing. Veri cation usually refers to those
activities that ensure that the current stage in software development is correctly built with respect
to previous stage. Validation refers to those activities that ensure that the current stage in software
development is correctly built with respect to the original requirements. A speci cation is complete
when all the required components are present and completely developed [10]. A speci cation is
consistent if its components does not con ict with each other [10]. Consistency and Completeness
of speci cation is inter-related and often inconsistency leads to incompleteness and vice-versa.

6
Requirement Analysis
and Design Coding Testing
Specification

Figure 1.4: The conventional software development paradigm

1.2.1 What is Testing?


What constitutes \testing" for a software system is closely tied to the paradigm used for its devel-
opment. Development paradigms for conventional software, for example, include several variants
of the Waterfall model [65] (e.g., the Spiral model [11]). In this class of models, testing (generally
referred to as veri cation and validation [57, 6, 61]) establishes a binary relationship between two
by-products of the software development process. For example, one type of binary testing compari-
son is between a speci cation (a description of the problem to be solved) and a design document (a
description of the functional decomposition, data structures and algorithms) [10].
The OO development paradigm can be mapped to Spiral model of software development. Thus,
testing in OO paradigm can be similarly de ned as a method of establishing a binary relationship
between two by-products of the software development such as between analysis and design or between
design and implementation. In the following, we discuss the reasons for testing being hard. We then
discuss testing related issues with respect to OO paradigm.
1.2.2 Why Testing is Hard?
Testing in general is a labor-intensive and fault-prone process [57]. Testing generally consists of the
following distinct steps.
1. Establish the criteria for testing.
2. Identify the target components for testing.
3. Generate appropriate test cases, where each test case consists of test input and expected
output.
4. Execute test cases against the target components and evaluate its outcomes.
The above steps are very much applicable in OO paradigm. The diculties associated with each
step of testing described above arise from unclear testing criteria, large input and output spaces,
and in generation of legal test cases.
Unclear testing criteria
Testing criteria de ne the goals for comparing a system against a speci cation. Black-box compar-
isons are based on the input and output alone without any consideration of, for example, \how" the
system solves the problem speci ed in the problem speci cation [57]. White-box comparisons, on
the other hand, use properties of the solution process of the system (such as a line of reasoning) as
a comparison criteria [57]. Some important testing criteria are:

7
 Testability: Testability is a measure of the ease with which other criteria for testing can be
established (e.g., robustness). For example, if the operative criteria for goal satisfaction are
absent in problem speci cation, testing is ill-de ned.
 Reliability: Reliability determines the extent to which a software system is solving the prob-
lem correctly. A system has high reliability if it consistently arrives at the expected solution for
a large proportion of problems speci ed in the problem speci cation according to the operative
criteria for goal satisfaction.
 Completeness: Completeness determines the extent to which a software system is solving
the correct problem. The completeness of a system with respect to the problem speci cation is
a measure of the portion of the speci cation implemented in the system. A system is complete
if it covers all the problems indicated in the problem speci cation.
 Robustness: Robustness is the extent to which a software system deteriorates gracefully at
the limits speci ed in the problem speci cation. Hence, robustness determines how a system
handles problems that are outside its de nition. A system has high robustness if it degrades
gracefully for problems not speci ed in the problem speci cation. For example, a system that
crashes with an unknown error code on an illegal input is not robust.
 Consistency: Consistency is the extent to which a software system, its problem speci cation,
and its solution speci cation do not have internal contradictions.
 Usability: Usability is the extent to which a software system is acceptable to some community
of users. One can have a perfectly working system, but if it does not meet the demand of users,
it will not be used.
The above testing criteria remains the same for OO programs. Thus, OO programs can be
treated as any other programs with respect to testing criteria.
Identi cation of components for testing
In procedural paradigm, the components that were subjected to testing were procedures and func-
tions, clusters of procedures and functions, execution paths, and the complete application as a whole.
However, in OO paradigm there new components that need to be tested such as classes and objects,
hierarchy among classes, methods, methods accessing instance variables and so on. In OO, the
method and message concepts are separated and due to dynamic binding of messages at run time,
the components are dicult to identify and generate test cases for them. The state of a system
is distributed among global variables, instance variables in each object, and variables supported
in local methods. Further, the execution paths in OO are much more dynamic than the paths in
conventional programs. Thus, OO paradigm o ers new challenges for testing.
Input and output spaces are huge
To test a selected component, a test case consists of a test input and its expected output [57]. For
the selection of test inputs and expected outputs, often these input and output spaces are very
huge. For example, in table 1.1 shows the potential input and output spaces for the expert systems
(and, therefore potential number of test cases) are large. Thus, selection of a reasonable set of input

8
System No. of Attributes Size of Size of
objects input space output space
MYCIN 17 257 3.4 x 106 6 x 106
INTERNIST 571 4100 4.0 x 10169
3.1 x 107
XCON 94 840 3.5 x 1029 2.1 x 10276
XSEL 79 329 5.0 x 1024 -
XFL 74 252 1.3 x 1023 -
Table 1.1: Sizes of possible input and output spaces (from Buchanan-88)

Generating a Problem Specification Problem specification specifies the


test case does not specify the crit- criteria for legal input
ria for legal input

Generate a No oracle oracle


legal input
case Almost impossible less difficult
Almost impossible

Table 1.2: Diculties in generating test inputs.

and output test cases that satisfy testing criteria from these huge input and output spaces can be
dicult.
The input and output space for generating test cases are huge even in OO paradigm. The path
space from which test paths need to be selected is also huge.
Generation of test case input is dicult
A legal test input is a test input that is consistent with the input speci cation in the problem spec-
i cation or requirements document. When possible input and output spaces are large, determining
legal inputs and outputs may be dicult. Although a problem speci cation may specify what a legal
test input is, it is generally dicult to specify how it can be generated. As table 1.2 shows it is
almost impossible to e ectively generate a test input when problem speci cation does not specify
the de nition of a legal input. If the problem speci cation speci es the legality criteria, an oracle
can be used to identify the legal test inputs. For example, the input part of a test case can be
generated by an expert (if she is available). Similarly, large number of archived test cases can be
used to generate both legal inputs and expected outputs (e.g., in the case of a medical data base).
Textbooks and domain literature may also be used to generate potential inputs. If there is no oracle,
it is almost impossible to systematically generate a test input.

9
Generating PS does not spe- PS does not but PS and SS specify
test case cify the legality SS specifes the the legality criteria
criteria legality criteria No oracle oracle

Generating Almost Difficult but


useless for Difficult Less difficult
expected impossible
output black-box testing

Table 1.3: Diculties in generating expected test outputs

1.2.3 Generation of Expected Output is Dicult


Since validation of a software system requires a large number of test cases, generation of expected
outputs for a legal input can be expensive. For black-box testing, the expected output consists of
an output for a given set of inputs. Domain experts can be used as oracles to generate expected
outputs for a given set of inputs.
If domain experts are not available, expected outputs can be generated from other sources such
as an explicit solution speci cation or design, archived test cases, text books or domain literature.
The generation of outputs from these sources, however, will in general be dicult. The generation of
expected outputs from arbitrary inputs can only be established in simple cases. The diculties for
generating expected outputs are similar to those for test case input and are summarized in table 1.3.
In white-box testing we need to trace paths through the software system in addition to compar-
ing inputs and expected outputs. Usually, there exists a large number of paths through a software
system. For example, in MYCIN [24] it is estimated that the minimum number of paths is approx-
imately 250,000. Given a legal test case input, the generation of an expected path from the large
set of possible paths is not obvious. Unlike expected output, path information is not available in
archived test cases, text books and domain literature. This problem of generating path based test
cases is more prevalent in OO paradigm.
Summary
Testing is dicult because the input and output spaces of software systems are usually large and
generation of legal input and expected output is dicult and often not obvious. In practice, how-
ever, the number of test cases actually required to achieve a high degree of reliability is small in
proportion to the size of possible input and the output spaces. This apparent discrepancy between
the astronomical size of the input and the output space and the number of test cases required to
achieve high reliability is interesting. Although the possible size of the potential input and output
spaces may be large for conventional software in most cases the number of test cases required to
establish high reliability is small when compared to the size of possible input and output spaces.
The key to e ective testing, therefore, is the strategy for generating appropriate sets of test cases.

10
1.2.4 Testing Techniques
As discussed in section 1.2.2, sizes of input and output spaces of software systems are enormous.
Even though a large number of test cases can be generated, testing and interpreting the test results
for all of them can be expensive. The objective of pragmatic testing is to reduce the number of test
cases and minimize the cost of testing without sacri cing the quality of testing.
A variety of pragmatic testing methods have been used to test conventional software ranging
from small programs to mission-critical software such as space shuttle software [6, 57, 71]. These
methods include for example random testing, equivalence and boundary partition testing, cause-
e ect graph testing, ablation testing, inspection and walkthroughs, auto-regressive testing. Each of
these methods speci es a strategy for generating and evaluating test cases to judge various aspects
of quality of program. In the following we brie y discuss each of the testing techniques.
Random testing
Random testing [57] generates test inputs randomly from input space. Although traditionally con-
sidered a weak method, its ease of generating test inputs and power of detecting failures in small
publicized programs have been noticed [20]. However, in another study it was found that random
testing may not be quite e ective on larger programs (or large sample space to select test cases)
that are more sensitive to special values [74]. For random testing to be e ective it must be easy to
generate expected outputs [46]. Furthermore, random testing works well on programs whose fault-
prone regions (input regions that result in failures) of the input space are large enough for adequate
random sampling. Random testing is also useful during early stages of software development when
system contains many undetected faults.
For a small-scale system, a small percentage of input space can be used to determine a good
estimate of the reliability of the system. However, for a large-scale system, random sampling of even
a small percentage of the input space can be prohibitive. It is therefore necessary to decompose a
large software system in such a way that various partitions of the system can be tested independently.
Random testing is applicable in OO paradigm for generating test cases for individual methods
and for method interaction within as well as across classes. Random testing can also be used to
generate test cases for message ow paths.
Partition testing (input or output based)
As opposed to random testing, partition testing is used to reduce the number of test cases required
by partitioning the input or output space into classes and sampling test cases from each class.
The success of partition testing depends on the presence of the speci cation and other by-products
generated within the development paradigm. In general, however, the partitioning criteria are not
obvious. An expert may be asked to partition the input and the output domain. If an expert is not
available, the generation of input and output partitions may be dicult.
The partition testing helps in pointing out potential failure-prone partitions of the input space.
Concentration on these partitions may reduce cost of testing. Output partition testing points out a
di erent set of potential failure prone regions of the output space. By concentrating more on these
partitions more failures can be found using less number of test cases. Because more failures help in
identifying more faults, partition testing can be potentially more cost e ective than random testing
when the software is no longer so error-prone. This is consistent with one of Myers' testing principles

11
in [57] that the probability of the existence of more faults in a section of a program is proportional
to the number of faults already found in that section.
Path related testing exploits the internal structure of a program in addition to input and expected
output. Path related testing methods include path based partition testing, cause-e ect graph testing,
white-box dynamic ow testing, data- ow dynamic testing and ablation testing. In the following we
discuss about these testing techniques.
Partition testing (path based)
Path based partition testing bases the partition on the path space of a program. Again, for parti-
tioning the path space one needs a good partitioning criteria. The partitioning of the path space
can be carried out with the help of an explicit solution speci cation. The path based partition test-
ing is usually limited by the availability of clear solution speci cation or design. In OO paradigm,
path based partition testing is very much applicable as there are huge number of paths through the
objects.
Each of the partitions in partition testing needs to be subjected to dynamic ow testing. Dynamic
ow testing not only checks for input and expected output but also ensures that an appropriate path
is taken by the program. The expected path is usually generated using design information. The
path is compared to the path followed by a software system in arriving at an outcome. This testing
is e ective for checking whether the program faithfully follows its design. A disadvantage of this
technique is that the e ort is proportional to the number of paths in the design.
Cause-e ect graph testing
Cause-e ect graph testing uses solution speci cation and the implemented solution to generate test
cases in an exhaustive fashion. Although this type of testing is not feasible for a complete system, it
can point out ambiguities and incompleteness in subset of solution (or problem) speci cations and
implementation. The exhaustive nature of this testing makes it particularly e ective for detecting
unanticipated side e ects [57]. This type of testing can also be used to demonstrate the quality of
the solution speci cation. However, for a large software system the cost of cause-e ect testing can be
enormous. A well decomposed software system can be more suitable for this type of testing. Since
in OO the system is decomposed into a set of objects or group of objects (clusters), cause-e ect
graph testing can be easily applied in OO paradigm.
Data ow testing
Data ow testing tests for path incompleteness, redundancies and ambiguities in an implementation.
In any software system, there can be several paths that are executed between de ne and use of a
data value. Data ow testing tests all paths between such a de ne-use (DU) pair. There exists
di erent variations of data ow testing based on the coverage criteria. The following criteria are
commonly employed for testing conventional programs [64, 60]
 All-c-uses: All the paths from a variable de ne to its use in a calculation.
 All-p-uses: All the paths from a variable de ne to its use as a predicate.
 All-uses: The union of all the paths derived from All-c-uses and All-p-uses.

12
 All-du-uses: All the loopless paths between a variable de ne and use are considered for testing.
Data ow testing is useful for detecting multiple paths between DU pairs. Data ow testing
is useful for identifying path related faults. For e ective data ow testing however, due to the
complexity of the implementation, additional reverse engineering tools may be required. Like other
path based techniques the cost of this technique is proportional to the number of DU-pair paths.
Data ow testing can be easily employed for testing OO programs. Data ows exist between the
methods of the same class and data ow test cases can be generated from them. Data ows also
exist between methods of di erent classes. The instance variables which participate in data ows
can be used for computation, for holding objects, or as a predicate.
Life-cycle testing
Life cycle testing addresses issues like when to stop testing (reliability testing), whether existing test
cases are sucient to detect certain kinds of faults (mutation testing), or whether an old feature
has been changed during software maintenance (auto-regression testing). Auto-regression testing
has been used extensively in industry to maintain and conventional software[3]. Reliability tests
can also be used in conjunction with mutation to evaluate both black-box and white-box testing
methods. In this section we discuss reliability testing.
As discussed in section 1.2.2 the size of input space of an expert system is huge. Because it is
not possible to exhaustively test such a space, only a small portion of the test cases has to be tested.
One method for estimating an appropriate number of test cases at AT&T is given in [43]. If Pt is
the desired quality level (for example, 80% accuracy) and ns are the number of test cases in a test
suite, the upper (Ps+) and lower (Ps;) 95 - percentile con dence levels are given by,
Ps+ = Ps + 1n:960 5 , Ps; = Ps ; 1n:960 5 and  = [Ps(1 ; Ps)]0:5
: :

where  is the variance of pass-rate and has a maximum value of 50 percent. Ps , the pass-rate is
s s

recomputed after running each test case. The crossing point of Ps+ and Pt determines the number
of test cases required for achieving the required quality of testing. The techniques reported in [43]
assume that test samples are homogeneous and test results follow a binomial distribution. It is
not clear that any software can completely satisfy these assumptions. However, reliability models
such as this can provide at least pragmatic hints for practicing engineers[4, 5] concerned with the
reliability of software with respect to certain testing techniques.

1.3 Related Research in OO Testing


In recent years, several techniques have been proposed for analysis, design, and implementation
of OO software. A recent survey article [54] mentions more than twenty OO analysis and design
techniques. The survey article provides a comparative evaluation of these techniques. But, none
of these proposed techniques explicitly address the V&V related issues in analysis, design, and
implementation. Meyer, in his research on 'design by contract' provides a rigorous usage of pre-
conditions, post-conditions, and invariants for specifying and implementing methods of a class [51,
52]. An excellent introduction to multiple interfaces for classes is given in [29].
OO paradigm being a new eld, not much research has been done in V&V of OO programs.
Majority of the research is in the initial stages of de ning the issues related to V&V of OO [8].
We can classify the testing related research into (1) introductory and de nition of issues in OO

13
testing, (2) Speci cation based OO testing, (3) Class and Cluster Related testing, (4) Data ow
based testing, (5) State based testing, and (6) techniques for managing the testing process.
Several issues related to V&V and maintenance of object-oriented programs are given in [68, 41].
A class testing using the algebraic speci cations of the classes is discussed in [27]. In [67], authors
use assertion de nition language (ADL) for class interface testing. Test case generation from OO
analysis and design products of OMT is discussed in [63].
OO integration testing using message-method pairs is discussed in [38]. However, in this article
authors do not discuss about test case generation and criteria of selecting message-method pairs from
the all possible pairs. In [55], there is a discussion on cluster and class testing. In this article, authors
discuss about test case management and execution using a scripting language. In [50], authors have
presented an integrated testing of OO programs with the software development process. In [49],
authors present an interaction testing technique that allows the tester to incrementally increase the
number of interactions for testing. In [2], authors discuss about their experiences with testing of
OO programs. In [7], there is a discussion on how to align developmental process with testing so
that designs are testable and testing is maximally e ective.
In [14], authors provide data related to testing of Smalltalk library software. The article in [72]
discusses various issues related to data ow anomaly testing at various levels in OO programs. In
[73, 32] authors discuss about state-based software testing of OO programs by modeling classes as
state machines. Issues related to adequate testing of classes is considered in detail in[62]. In [30],
there is a discussion on hierarchical incremental testing of classes. In [69], authors discuss about
a framework for testing OO programs. In [15, 16] authors have provided a set of metrics suite for
object-oriented design. These metrics are useful for the analysis of OO programs and for testing.

14
Chapter 2

Method and Message Sequence


Speci cation
Object-oriented analysis and design methodologies examine the problem in the problem domain
and facilitate in decomposing the problem in terms of classes, objects, and the relationships between
them. The result of any OOA and OOD technique is a speci cation of the system under construction.
OOD re nes and expands the speci cation generated from OOA. The primary goal of many OOD
techniques proposed to date is to facilitate easy construction of classes during the implementation
phase.
It is dicult to capture the details of a complex system in one structural design. Therefore,
OOD techniques model a complex system using domain classes, class hierarchy, static models (such
as module diagrams), dynamic models (such as state-transition diagrams and event diagrams). The
primary objective of OOD techniques is geared towards decomposing the analysis objects for easy
implementation. In this thesis, we propose a new speci cation that can be incorporated as a part
of any design techniques called Method Sequence Speci cation (MtSS) and Message Sequence Speci-
cation (MgSS). The MtSS and MgSS model the dynamic behavior of the objects in a system.
Many OOAD techniques strive to separate the implementation details of a system from the
speci cation. In \Design by Contract" technique, the output of OOAD is a contract between de-
signers and implementors [52]. Another OOAD technique based on responsibilities also suggests
using responsibilities as a contract of the speci cation of publicly available services [77].
The contract speci cation and separation of the speci cation from the implementation is useful
in several ways. Clear speci cation help implementors to deliver the software as promised in the
contract. The contract speci cation also helps in documenting a class as a library component, thus
promoting reuse. For multi-person projects the speci cation can be used as a shared knowledge
before implementing di erent portions of a software. But all the above techniques does not address
the issue of test case generation from the contract speci cation. The contract speci cation can be
easily extended to assist in test case generation and easy maintenance. In this thesis, we propose
the MtSS and MgSS that can be integrated as a part of the contract speci cation of classes and
used for test case generation.
The contract speci cation of a class details a contract between the environment and its imple-
mentation. The contract should specify everything an external user should know for the correct use

15
of the class and everything an implementor should know for proper implementation of the class.
Even though the complete contract speci cation is of much interest, in this thesis, we concentrate
on the MtSS and MgSS of the classes.
In section 2.1 we describe MtSS with respect to a single class. The MtSS of a class documents
the correct causal order in which the methods can be invoked by the class instances. We then
introduce MgSS to include the instance methods supported by multiple classes. MtSS and MgSS
of classes document the message-method interaction and the correct sequence in which messages
can ow through class instances. The primary goal of MtSS and MgSS is to facilitate the V&V of
classes. In later chapters we use MtSS and MgSS for test case generation, data-anomaly detection,
and run-time veri cation of the instances.
In section 2.2, we discuss about deriving MtSS of a class from the products of analysis and
design. MtSS is not a complete speci cation of the classes, but captures only those components that
are necessary for V&V. The MtSS represents the method interactions, i.e. the dynamic interaction
between the class instances. We then discuss the deriving of MtSS of a class from the state based OO
design. MtSS can also be derived from the dynamic models built during design such as Interaction
Diagrams [12], Event Trace Diagrams [66], or Use-Case Diagrams [37].
De nition 2.1 Methods(C): For a class C we de ne Methods(C ) as a set of all the instance meth-
ods de ned in C that are publicly available.
Example: For a Stack class the method set can be, Methods(Stack) = fpush, pop, isempty?, isfull?,
top g

2.1 Method Sequence Speci cation (MtSS)


Instances instantiated from classes support a set of methods that can be invoked by sending messages
from other client objects. Each object maintains a state. The state of an object is modi ed when
an instance method of the class changes the attribute value of the object. When an object receives
a message, the result of the execution of a method in response to the received message depends on
the state of the object. The state of an object depends on the set of methods the object has already
executed which depend on the messages the object has already received. Thus, the object state and
behavior depend on the sequence in which the methods are invoked. The correct object behavior
is possible only if the methods are invoked in a correct well-de ned sequence. In this section, we
describe the MtSS for specifying the relationship between the methods of a class.
Methods of a class can have di erent types of inter-method relationships. The causal relationship
between the methods specify the sequence in which the methods can be invoked such as the method
m1 must be invoked before the method m2 . We use MtSS for specifying this causal relationship.
The MtSS of a class is important as it speci es the correct sequences in which objects of the class
must invoke its methods. The methods can also have a time-based relationship such as the method
m1 must be invoked within 20 milli seconds after the method m2 . In this thesis, we model only the
causal relationship between methods. We use regular de nitions [1] to model the causal relationship
between methods. For modeling the timing relationship between methods we need more powerful
formalism than the regular de nition.
The strict sequence rules between methods of a class depends on the functionality of the class.
For example, the instances of a Stack class should receive a rst pop() message only after receiving
a push() message. Some of the ordering rules can be due to implementation issues. For example in

16
C++ objects must receive a constructor message before receiving any other messages, and a delete
message must be the last message. All other messages must be received between these two types of
messages.
To represent the method sequence speci cation of a class C we use regular de nition over the
alphabet (usually referred as ) consisting of methods from Methods(C ). The regular de nition is
a set of de nitions of the form
l1 ! r1
l2 ! r2
:::
ln ! rn
where, each li is a distinct label, and each ri is a regular expression over the methods in Methods(C )[
fl1; l2 ; : : : li;1g. In a regular expression the methods are separated by '' or 'j' operators. In a regular
expression, two methods m1 and m2 related as m1 m2 implies that there is a sequential order between
m1 and m2 and m1 is before m2. In the context of methods and MtSS, it means that the method m1
is invoked before the method m2 is invoked. Similarly in a MtSS, two methods m1 and m2 related
as m1 jm2 implies that either of the methods can be invoked rst, but not both. The operator 'j' is
an exclusive-or operator. The regular expression can use symbols such as '*' for specifying zero or
more instances, and '+' for specifying one or more instances of a method or group of methods. The
regular de nition associated with a class de nes all the valid method sequences that the object can
invoke.
De nition 2.2 Method Sequence: We de ne a method sequence S as a nite sequence over a method
set M of C , (m0  m1  : : :  mn), where each mi 2 M . A method sequence need not contain all the
methods in the method set. The entries in a method sequence corresponds to a causal order in which
the methods get invoked.
Example: In the above Stack class a possible method sequence is (push  top  pop  isempty?). In
this method sequence the method push is invoked before the method top is invoked for all instances
of class Stack.
De nition 2.3 SeqSpec(C ): A SeqSpec(C ) is the speci cation of C that de nes a sequence rela-
tionship between all the methods of C . We use regular de nition for specifying the SeqSpec(C ). We
also use REC to refer to regular de nition.
Example: Let us consider a speci cation of a simple bank account class as shown in gure 2.1. The
interface methods de ned in Account class are,
 = fcreate; deposit; open; withdraw; close; deleteg
where, create and delete methods are constructor and delete methods, open method is used for
opening an account, deposit method is used for depositing positive sums of money into the account,
withdraw method is used for withdrawing money from the account, and close method is for closing
the account. In the following we describe a MtSS for the Account class. In the sequence speci cation,
the regular de nition labels such as AccountMethods are present on the left hand side of the arrow.
The SeqSpec(Account) is,
SeqSpec ) create  AccountMethods  delete
AccountMethods ! open  TransactionMethods  close
TransactionMethods ! (deposit  (depositjwithdraw)) (2.1.1)

17
Account Class
Account_No
Name
Balance
Open( )
Close( )
Deposit( )
Withdraw( )
Create( )
Delete( )

Figure 2.1: Account Class attributes and methods

In the above sequence speci cation (equation 2.1.1), create is the rst method the instance
of Account class executes before executing any of the other methods. Once the method open is
executed, the instance can execute either deposit or withdraw method and for any number of times
before executing the close and delete methods. Thus, the MtSS of Account class indicates the causal
order in which the methods can get executed for the correct behavior of instances of the class.
De nition 2.4 SafeSeq(C ): A SafeSeq(C ) de nes a set of all sequences Si that can be derived
from SeqSpec(C ) of the class C . A sequence in SafeSeq(C ) is a valid sequence of messages ac-
cepted by any instance of the class C . SafeSeq(C ) is the regular set (or the language) de ned by
SeqSpec(C ).
Example: The sequence speci cation of Account class given in the previous example de nes all
possible valid sequences of messages that an object of class Account can receive. This set of sequences
is SafeSeq(Account). For example, a safe sequence set with sample sequences are,
f(Create  Open  Deposit  Withdraw  Close  Delete),
(Create  Open  Deposit  Deposit  Withdraw  Close  Delete);: : :g
2.1.1 Properties satis ed by MtSS
In this section, we give a set of properties satis ed by any MtSS of a class. These properties are
derived from regular de nitions and therefore, these properties will not be discussed in depth.
Property 1: For any given three methods m1 , m2, and m3 of a class, then in the MtSS of the class
it is true that
m1  (m2  m3 ) = (m1  m2)  m3 = m1  m2  m3
In Property 1, the brackets does not change the causal order in which the methods get invoked.
Property 2: For any given three methods m1, m2, and m3 used in a MtSS of a class, the operators
'' and 'j' are distributive. i.e.
m1  (m2jm3 ) = (m1  m2)j(m1  m3)

18
(m1jm2 )  m3 = (m1  m3)j(m2  m3)
We use the above properties throughout this thesis.

2.2 MtSS Derivation from Design


Many OO analysis and design techniques specify the dynamic interaction between objects using
dynamic models. The commonly used dynamic models are State Transition Diagram (STD), Object
Diagram, Event Trace Diagram, and Use-case Diagram. For example, OO Analysis and Design
technique from Booch [12] prescribes STD, object diagram, and interaction diagram for capturing
and modeling the dynamic behavior of the objects. Similarly, Iverson's Use Case diagram captures
the dynamic interaction between the objects.
In this section, we describe techniques for deriving sequence speci cation from the dynamic
models such as STD and Booch's Object diagram. Similarly , sequence speci cation can also be
derived from Event diagram.
2.2.1 MtSS from State Transition Diagram
Many OO analysis and design techniques propose State Transition Diagrams (STD) for modeling
the dynamic behavior of classes [12, 66, 19, 79]. STDs can be used to model both inter-class and
intra-class dynamic behavior [19]. For deriving MtSS of a class, we use its intra-class STD. The
STD model represents all possible states of the class, the events that can cause state transitions,
and the actions that result from the state change. The STD model for a class describes how the
time sequencing of external events can a ect the state of an object of the class.
Di erent states of an object are due to the di erent value combinations of the attributes. The
states are linked to one another through state transitions. State transitions are caused by the
events which are the stimulus received from the environment. Thus, di erent values of the instance
attributes de ne states of an object and the messages received from the environment are the events.
At each state, all the events are unique and events can be received in any state. The state transition
depends on the current state and the message received. In analysis and design, STDs contain states,
events, and actions.
The MtSS for a class can be derived automatically from the STD speci cation of the class. For
deriving MtSS, we use only the events. We do not consider the states and actions associated with
state transitions. STDs (similar to nite automata) can be modeled as a 5-tuple (S ; ; ; s; f ), where
S is a nite set of states,  is the set of methods accessible from the outside environment, s 2 S is
an initial state corresponding to the state after a class receives a constructor message, and f 2 S
is a nal state corresponding to a class receiving a delete message, and  is the transition function
mapping S   to S .
The sequences of messages accepted by such an STD of a class C , forms the SafeSeq(C ).
Construction of regular de nitions that accepts the same language as that of an STD is well studied
in literature. Several ecient algorithms exists for deriving the regular expression from the STD (see
theorem 2.4, page 33 of [34]). As STDs are constructed for each class during analysis and design
phases, these STDs can be used for generating the sequence speci cation of the class. Because
the ecient algorithms are available, an easy tool support can be provided for deriving a method
sequence speci cation of a class. In the following, we illustrate the MtSS derivation from the STD
of class Account.

19
Withdraw ( )
Operation Deposit ( )
Account
Deposit ( )

Open ( ) Empty
Start Account Close ( )

Null
Account

Figure 2.2: STD corresponding to Account Class

Example: Account class


In the example given in the last section, the methods and attributes of class Account were described.
The STD corresponding to the dynamic behavior of class Account is given in gure 2.2. The STD
consists of four states with four types of events each corresponding to messages1. The method open
creates an empty account. The deposit method creates an actual operational account. Once an
operational account is created, deposit and withdraw methods can be invoked until the account is
closed. The regular expression that can be derived automatically from the STD is:
(open  deposit  (depositjwithdraw)  close)
This regular expression is the MtSS for the class Account.
2.2.2 MtSS from Object Diagram
The Object Diagram forms an important notation in Booch's OO analysis and design method [12]
to show the existence of objects and their relationships. In this section, we describe a set of rules for
deriving the MtSS from an Object diagram. An Object diagram represents interactions between class
instances. In addition, Object diagrams are used for capturing the semantics of the logical design
of the system. Each Object diagram consists of two essential parts: objects and their relationships.
Objects
Objects are represented using 1) object name only, 2) object class only, or 3) object name and class.
For example, for an object A of class C, the object is represented as A, :C, or A:C. Several objects
of the same class can be present on the same object diagram. If the class of an object is not speci ed,
then the class is considered anonymous. For some objects, some of its attributes may be shown.
1 The methods for creation and deletion are not shown in the gure 2.2. The create method can be associated to
start state and similarly the delete method can be associated with end state of the STD.

20
Object relationships
In an OO system, objects interact with other objects. A link is used to model the relationship
between objects. A link is an instance of an association. A link exists between two objects, if and
only if there is an association between the corresponding classes of the objects. The existence of
association between classes indicate the existence of communication between the instances of the
classes. Thus, an object can send messages to other objects or to itself.
Objects can be classi ed as client or supplier objects with respect to a relationship between the
objects depending on the direction of message ow. For example, if two objects O1 and O2 are
related through a link L, O1 can invoke any of the methods supported by O2 that is accessible to
O1 . For a given method m1, if a method in O1 invokes m1 supported by O2 then, O1 is considered
the client object and O2 is considered the supplier object with respect to m1 .
In an Object diagram, each message is marked with three kinds of information.
 A synchronization symbol denoting the direction of the invocation.
 Message invocation or an event dispatch.
 A pre x sequence number.
The pre x sequence number is an optional one. In the absence of an explicit sequence number,
messages may be sent at any time relative order to other messages. The sequence number indicates
the relative ordering of the messages. Messages with the same relative number are unordered with
respect to each other. The message with a higher sequence number is dispatched later compared to
a message with a lesser sequence number.
For generating the MtSS of a class, we use the sequence number that is pre xed to the message
name. The MtSS is generated class by class. For a given object instance of a class, the MtSS of the
class is derived from the Object diagram as follows:
 If s1 and s2 are the sequence numbers of the methods m1 and m2, and s1 = s2 , then the
corresponding MtSS containing the methods are, (m1jm2).
 If s1 and s2 are the sequence numbers of the methods m1 and m2 , and there exists no method
m3 with sequence number s3 such that s1 < s3 < s2, then the MtSS containing m1 and m2
are, (m1  m2).
 If a method m1 has no sequence number, and M is the MtSS of the class derived from the rest
of the methods, then the MtSS of the class containing the method m1 is, (m1jM ).
In gure 2.3, the Object diagram for an Account class instance is shown. The messages sent
to instance of the Account class is marked with the sequence number. The deposit method has
two sequence numbers 2 and 3 indicating that it is invoked twice. The methods deposit, withdraw,
accSumm, and balance have a same sequence number indicating that any of these methods can be
invoked in any order. Using the above rules, the partial MtSS that can be derived is,
MtSS ) open  deposit  (depositjwithdrawj
accSummjbalance)  withdraw  close (2.2.2)
The Object diagram indicates only the causal order between the methods. However, it does not
have any notation to indicate that some methods may be repeatedly invoked. For example, a deposit

21
:ATM :Cashier

Cashier
ATM operations
operations

1:open

2,3:deposit

3,4:withdraw
:Bank :Account
3:accSumm

3:balance

5:close

Figure 2.3: Object Diagram for Account Class

method of an Account class may be repeatedly invoked before invoking any other method supported
by the class. However, MtSS allows to model concepts such as 0 or more times, or 1 or more times
invocation. Therefore, once the MtSS is derived from the Object diagram, one has to group some of
the methods and identify a proper repetition symbol. In the following, we expand the example that
illustrates the above concepts.
The MtSS shown in equation 2.2.2 is derived from the Object diagram drawn in the gure 2.3.
This MtSS shows the causal order between all the methods supported by the Account class. From
this MtSS, we need to expand it to re ect that an instance of the Account class can receive several
deposit or withdraw messages before receiving a close message. i.e. the methods inside the parenthesis
in equation 2.2.2 can be invoked any number of times. Therefore, the modi ed MtSS is,
MtSS ) open  deposit  (depositjwithdrawj
accSummjbalance)+  withdraw  close (2.2.3)
The + sign after the parenthesis indicates that any of the methods can be invoked more than
once in any order.

2.3 Message Sequence Speci cation (MgSS)


The MtSS discussed in previous section captures the causal order in which methods of an instance
of a class can be invoked. In an OO system, there exists several objects and MtSS identi es only the
causal order of the methods supported by the instances of the same class. MtSS does not specify
the causal order that exists between the methods supported by di erent classes. In this section, we
discuss the Message Sequence Speci cation (MgSS) that can be used to describe the causal order
among the methods supported by di erent objects.

22
o2:C2

m2

m1 m3
o1:C1 o3:C3

m4

o4:C4

Figure 2.4: Diagram for illustrating MgSS

The MgSS is speci ed for each of the method that sends out messages. MgSS and MtSS together
can identify the causal order between any two methods de ned in two di erent classes. Since MgSS
for a method that sends out no messages to other objects is null, MgSS is useful for those objects
that behave as client objects to other objects.
The MgSS of a method identi es all the messages it sends out to other domain objects. It also
identi es the causal order in which the messages are sent out. For the MgSS speci cation we use
the same regular expression formalism used for MtSS. In addition to all the operators ' ', 'j', '+',
and '*' we introduce a new operator '?' that indicates that a message pre xed to operator '?' is
optional. In the following we describe MgSS of a method of a class.
Figure 2.4 contains four objects O1, O2, O3, and O4. The method m1 of O1 sends messages
to O2, O3, and O4. The order in which messages m2, m3, and m4 are sent out to objects by the
message m1 forms the MgSS of the method m1. If the messages are sent out in the order of m2,
m3, and m4 then the MgSS of m1 is,
m1O1 ) (m2O2  m3O3  m4O4) (2.3.4)
If the messages are sent out as either m2 or m3 as rst before m4 then, the MgSS of m1 is,
m1O1 ) ((m2O2jm3O3 )  m4O4) (2.3.5)
During design phases, MgSS of methods might identify only the important messages that a
method sends out to other objects. Thus, in implementation of the method, it might send additional
messages to other objects.
For a given method, MgSS of the method can be determined based on the way it interacts with
other objects. In the following we brie y discuss how di erent scenarios lead to di erent MgSS.
1. If a method sends out messages to objects one after the other, then all the messages are

23
represented in the order in which they will be sent out. For example, if m1, m2, and m3 are
sent out in a sequence then the corresponding MgSS will be m1  m2  m3.
2. If a method sends out a message optionally and other messages always, the optional message
will be represented in MgSS using the operator '?'. For example, if m1 is sent out optionally
and then m2 and m3 are sent out, then the MgSS will be m1?  m2  m3. When messages are
predicated on conditions, messages are sent out optionally.
3. If a method sends out messages alternatively such as, a true condition results in one message
and false condition results in another message, the the MgSS will contain both the messages
as alternative messages. For example, if m1 or m2 is sent out, but not both, then the MgSS
corresponding to the above condition is, m1jm2.
4. If a method sends out messages repeatedly such as messages in a loop, then the operator '?'
or '+ is used. The operator '? is used when messages are sent out zero or more times, while
the operator '+' is used when messages are sent out one or more times. For example, if a
message m1 is sent out repeatedly one or more times, then followed by a message m2 then the
corresponding MgSS is, (m1+)  m2.
The MtSS and MgSS together identify the causal order between any two methods of any objects
as long as both these methods are on the message ow from the starting method. The MtSS and
MgSS is used extensively in this thesis for test case generation.
2.3.1 MgSS and MtSS from Interaction Diagram
Interaction diagrams are used in many OO analysis and design techniques for representing the
interaction between objects [37, 12]. In [37], authors use Interaction diagrams for representing the
use cases. Use cases are used predominantly for representing the analysis and design information.
Interaction diagrams are used to describe how each use case will be implemented by communicating
objects. In this chapter we use the Interaction diagrams as given in [37] and provide an outline for
deriving MgSS and MtSS.
Interaction diagram
Interaction diagrams are used to describe how an use case can be realized through communicating
objects. The interactions take place when objects send messages (stimuli) between them. To realize
a use case, a set of objects (blocks) are initially identi ed. These blocks are represented by a vertical
column in the Interaction diagram. A special column is shown di erently for the system border or
the interaction border with other interaction diagrams. The time axis is viewed as going downwards.
Thus, the Interaction diagram starts with the description at the beginning of the diagram. On the
left of system border, the use case descriptions are given and on the right side of the system border,
the use case realization using messages is shown.
The Interaction diagrams are controlled by the events owing between the blocks. The events
are stimuli, i.e. messages sent from one object to the other object. The stimulus is shown by a
horizontal line with an arrow, starts from the block that initiates the stimulus and ends at the
block corresponding to the receiving object. The vertical block diagram shown on each vertical line
corresponds to the scope of the operation.

24
System Border ATM ATM Hardware Bank Account

withdraw readAmt
Withdraw Request

withdrawReq getAccInfo
get Account Info.
get Account Summ
Check balance. getAccSumm
If appropriate,
issue withdraw.
balance

If withdraw is succ. withdraw


dispense Cash. dispCash
Return Status status

Figure 2.5: Deriving MgSS from Interaction Diagram: Example

In gure 2.5, an Interaction diagram for the ATM example is shown. This Interaction diagram
realizes the 'withdrawing of the money' use case. The blocks involved in the interaction diagram
are ATM, ATM Hardware, Bank, and Account. The ATM block corresponds to a software class that
interacts with the ATM Hardware block. ATM Hardware interfaces with the actual hardware. When
the block ATM receives a withdraw request, it initially gets the requested amount and then checks
with the account whether there is enough money for the withdraw. If the withdraw is possible, then
a cash dispensing request is sent to the ATM Hardware.
Deriving MtSS from withdraw use case
The MtSS corresponds to the causal order in which methods at an object are invoked. In the
interaction diagram 2.5, only one use case is shown and thus the MtSS generated from the above
is not complete. However, once all the use case depictions are available, one can generate the MtSS
completely.
To determine the MtSS for each of the class, the events incident on the block corresponding to
the class is considered. For example, to determine the MtSS of ATM Hardware, we consider the block
corresponding to ATM Hardware. The events incident on ATM Hardware are readAmt and dispCash.
The causal order is determined by the order in which the events are generated, whether the events
are conditional or in a loop and so on. Information whether the events are conditional or not is
provided by the use case description attached on the left side of the border line. Using the above
technique, MtSS for all the blocks are given below:
MtSSATMHardware ) readAmt  dispCash (2.3.6)
MtSSBank ) withdrawReq (2.3.7)
MtSSAccount ) getAccInfo  getAccSumm 

25
balance  withdraw (2.3.8)
Deriving MgSS from withdraw use case
To derive MgSS from Interaction diagram for each of the methods (events), the events that are
going out from a block are considered. For example, at the block Bank, various events go out
such as getAccInfo. Once all the out going events are known, then the causal order among them
is determined. For determining whether some of the outgoing events are optional or whether they
are repeated multiple times, the use case descriptions are read. The MgSS derived for some of the
methods (event) is shown below:
withdrawATM ) readAmtATMHardware  withdrawReqBank 
dispCashATMHardware (2.3.9)
withdrawReqBank ) getAccInfoAccount  getAccSummAccount  balanceAccount
withdrawAccount (2.3.10)
In the MgSS generated for the withdraw()(see equation 2.3.9), three messages are sent out to
di erent classes and the causal order among them is identi ed.

26
Chapter 3

Consistency and Completeness of


MtSS and MgSS
Veri cation and Validation (V&V) of software includes all those activities performed on the life-cycle
products that increase the quality, reliability, and usability of the software. It is well known that
extensive V&V is essential for developing reliable software. The development of software involves
various production activities where opportunities for introducing faults by human mistakes is enor-
mous. It has been observed that software constructed from an unreliable speci cation requires major
resources and cost during V&V [6].
The importance of speci cation Consistency and Completeness (C&C) is well known in software
engineering. Design and construction of software speci cation is a highly iterative process. Because
the speci cation for software is written by humans it is bound to contain gaps and contradictions.
The speci cation is also subjected to continuous changes due to the changing environment and
new requirements. Further, software being complex, the speci cation must represent complex re-
lationships and associations of the software that is being implemented. Thus, manually developed
speci cation may contain several inconsistencies. Inconsistency and incompleteness in MtSS and
MgSS would lead to faulty implementation and therefore, C&C of the speci cation is essential for
developing OO systems with less faults.
MtSS and MgSS can be derived semi-automatically from OO analysis and design products and
in that process, MtSS and MgSS may contain inconsistencies. Therefore C&C of the speci cation
is essential. Further, if there are inconsistencies in the original OO analysis and design products,
identi cation of the inconsistencies in MtSS and MgSS can be traced back to the analysis and design
products. Thus, C&C of MtSS and MgSS help in identifying faults in the analysis and design. In
this thesis, we provide a set of rules for checking the consistency and completeness of MtSS and
MgSS in the presence of single and multiple inheritance. We then extend the rules to check the
consistency and completeness in the presence of multiple interfaces to a class.
Inheritance relation is used extensively in OO based applications. OO languages support inheri-
tance to model the hierarchical relationship between classes as well as to promote code reuse[28, 51,
70, 22, 12, 42]. Inheritance allows a class de nition to use the de nition of one or more other classes.
If a class C1 directly inherits from another class C2 , then C1 is called the child class and C2 is called
the parent class. A child class inherits the speci cation of the parent class. It is possible that the

27
parent and child class speci cation may be inconsistent with one another and therefore consistency
veri cation between the parent and child class speci cation is essential. In this thesis, we propose
consistency rules that can be used to verify the consistency between the MtSS of the parent and
child classes depending on the type of inheritance.

3.1 Inheritance and C&C of MtSS


In inheritance, a child class inherits both the operations and instance variables de ned in parent
classes. A child class, in addition to inherited methods, can further enhance the class with addi-
tional operations or change the implementation of inherited methods [70, 51]. Inheritance can be
used for specialization, re nement, and implementation (reuse) [51, 70]. If inheritance is used for
specialization, then the child class satis es the semantics of all the inherited methods from the par-
ent class1. A child class may be extended with additional methods and instance variables. Thus, a
child class does not modify the semantics of the inherited methods and obeys the inherited methods
protocol. In Ei el, the specialization inheritance can be ensured with the help of pre-conditions
and post-conditions for the parent class methods [51]. If inheritance is used for re nement of the
parent class, then the child class may modify the semantics of the inherited methods. Thus, the
inherited methods are re ned or modi ed and the behavior of child class methods may be di erent
from the behavior of the corresponding methods in the parent classes. If inheritance is used for
implementation, then the child class may not inherit all the methods from the parent class, and may
modify the semantics of the inherited methods [70, 42].
In this thesis, we propose a set of C&C rules for consistency checking of MtSS of classes for each
type of inheritance. Let C1; C2 ; : : : Ck be a set of classes that are related to one another through
inheritance relationship. In the following, we de ne terms that are used in C&C rules.
De nition 3.1 -instantiate(MtSS; S ): -instantiate(MtSS; S ) is de ned as an operation on the
MtSS where it instantiates all the methods of S in MtSS with .
As and example, if MtSS of a class is m0  m1  (m2jm3), and S = fm1; m3g, then, -
instantiate(MtSS; S ) = m0  (m2).
De nition 3.2 Language(MtSSC ): Language(MtSSC ) de nes a set of valid method sequences
that can be generated from the sequence speci cation MtSS.
For example, if MtSS of a class C is m0  (m2jm3), then Language(MtSSC ) = f(m0  m2); (m0 
m2  m3); : : :g.
De nition 3.3 Subseq(s1; s2 ): A boolean function returning true if s1 can be formed by deleting
zero or more not necessarily contiguous methods from s2 .
For example, if s1 = m0  m2, and s2 = m0  m1  m1  m2  m3 then, Subseq(s1; s2 ) is true because
s1 can be derived from s2 by deleting m1 and m3 from s2 .
1 In this thesis we are using the inheritance model of SmallTalk. In C++, there are public, private, and protected
categories of methods and private methods are not inherited from the parent classes.

28
3.1.1 Specialization Inheritance and MtSS
In specialization inheritance, a child class can add new methods, in addition to all the inherited
methods from the parent classes. The child class inherits all the public methods of the parent class
and does not modify them. Let, class Ck be a proper child class of C1 : : : Ck;1.
The MtSS for the child class Ck must obey the MtSS semantics of all its parent classes. In class
Ck , the Methods(Ck) can be split into newly added methods and inherited methods. i.e.,
De nition 3.4 NewMethods(Ck): A set of methods that are newly added in class Ck and not
inherited from the parent classes of Ck .
De nition 3.5 InhMethods(Ck; Ci ): A set of methods of class Ck that are inherited from class Ci
6 Ci.
and Ck =
De nition 3.6 IM (Ck ): A set of methods of class Ck that are inherited from all its parent classes
C1 : : : Ck;1.
In specialization inheritance, the child class inherits all the parent class methods. Therefore a
completeness rule is,
Rule 3.1 IM (Ck ) = [ki=1 ;1Methods(Ci).
The MtSS of the child class must be consistent with the MtSS of the parent classes. But,
the MtSS of the child class might include many new methods. Therefore, the child class MtSS is
consistent with all the parent class MtSS if any valid method sequence in the parent class is a proper
subsequence of at least one method sequence of the child class. A rule that veri es the above is
given below:
Rule 3.2 Let, Ck be the proper child class of the parent classes, C1 ; : : : ; Ck;1,
Si = NewMethods(Ck) [ fIM (Ck ) ; InhMethods(Ck; Ci )g, and
NewMtSSi = -instantiate(MtSSC ; Si ), where, i = 1; : : : ; k ; 1.
k

Then,
8ik; Language(MtSSC ) = Language(NewMtSSi )
1
=1 i

In the above rule, the set Si includes the methods inherited from all other classes except Ci,
and the new methods introduced in Ck . Using the set of methods in Si, a new MtSS is constructed
called NewMtSSi containing only those methods of Ck that are inherited from Ci. Because in
specialization inheritance, the methods are not modi ed, the derived MtSS must be same as the
MtSS corresponding to class Ci.
The above rule uses operations on MtSS for representing the C&C rule. MtSS uses regular
expression syntax for representation. Therefore, the above rule can be easily implemented using
simple operations on regular expressions such as equality, inclusion, and di erence between two
regular expressions. In section 3.3 we provide a general algorithm for implementing such operations
on regular expressions. The rules can be implemented using these described algorithms.
A single inheritance is a specialized case of the multiple inheritance. The consistency rule between
the MtSS of the parent and child class is similar to the one given above. If C2 is the child class of
C1 then the MtSS of C2 given the MtSS of C1 must satisfy the following rule.

29
Rule 3.3 If MtSSC1 and MtSSC2 is the MtSS for classes C and C ,
1 2
S is the NewMethods(C ), and
2
NewMtSS = -instantiate(MtSSC2 ; S ) then,
Language(MtSSC1 ) = Language(NewMtSS ).
Informally in the above rule, the MtSS of the modi ed child class with only the methods inherited
from the parent class must be equal to the MtSS of the parent class. This is because, the child class
do not modify the semantics of the methods in the parent class.
Specialization inheritance:Example
Let us consider the class Account that supports six methods. The sequence speci cation of the
Account class is,
MtSSAccount ) create  open  (deposit 
(depositjwithdraw)?)  close 
delete (3.1.1)
Let us consider a new class Checking Acc that specializes the parent class Account through spe-
cialization inheritance. In this case, the Checking Acc class inherits all the methods of the parent
class Account. Further Checking Acc may be enhanced with new methods, for e.g., balance(), and
report(). The MtSS of the class Checking Acc is,
MtSSChecking Acc ) create  open  (deposit 
(depositjwithdrawjbalancejreport)?) 
close  delete (3.1.2)
The consistency between the MtSS of Checking Acc class and the MtSS of Account can be checked
here. The child class Checking Acc contains two new methods and if they are replaced with the null
methods, we get the Account class MtSS. Thus, by applying the above consistency rule for single
inheritance, we see that the MtSS of Checking Acc class is consistent with the MtSS of Account class.
i.e., the regular expression of Account class can be derived from Checking Acc class by substituting
those methods that are newly added in Checking Acc with .
3.1.2 Re nement Inheritance and MtSS
In re nement inheritance, the child class modi es the semantics of some of the inherited methods
from the parent classes. Modi cations in the inherited methods can be either in the method protocol
(also known as method signature) or behavior. The two corresponding methods in the parent and
child class that are related through inheritance, may produce di erent results for the same set of
inputs. For representing the methods that are re ned in the child class we de ne the following term.
De nition 3.7 RefMethods(Ck; Ci): A set of methods in Ck inherited from Ci, whose implemen-
tation are modi ed.
C&C of MtSS of the parent and child classes that are related through re nement inheritance is
similar to the one described in section 3.1.1. The di erence is in the computation of the set Si. For

30
Account
Methods: Open, Close, Deposit, WIthdraw
Create, and Destroy

Savings New Methods: Balance, Report


Account Refined Methods: Deposit, Withdraw

Figure 3.1: Example Illustrating Re nement Inheritance

the C&C rule in the case of re nement inheritance, the Si must include the RefMethods(Ck; Ci)
where i = 1; : : : ; k ; 1. Informally, the inherited methods that are re ned must be considered as
new methods of the child class and must not be considered while applying the rule. Similarly, those
methods in the parent class that are re ned in the child class must not be included in the parent
class MtSS for applying the consistency rule. The rule is,
Rule 3.4 Let, Ck be the proper child class of C ; : : : ; Ck; ,
1 1
Si = NewMethods(Ck) [ RefMethods(Ck; Ci ) [ fIM (Ck)
; InhMethods(Ck; Ci )g, and
ChildMtSSi = -instantiate(MtSSC ; Si), where, i = 1; : : : ; k ; 1, and
ParentMtSSC = -instantiate(MtSSC ; InhMethods(Ck ; Ci)), then
k

;1Language(ParentMtSSC ) = Language(ChildMtSSi)
8ki=1
i i

In the above rule, the ChildMtSSi is the MtSS containing only those inherited methods from the
parent class Ci that are not re ned. The ParentMtSSC is the MtSS of the parent class containing
i

only those methods that are not re ned in the child class. For the consistency rule, these two MtSS
must be equal.
Re nement inheritance: Example
In gure 3.1, the child class Savings Acc re nes some of the methods inherited from the parent class
Account. The methods Deposit and Withdraw of the parent class are modi ed to compute interest.
The speci cation of child class can be veri ed against the parent class by considering these two
methods as new methods in Savings Acc class and not considering them for the rule application.
3.1.3 Inheritance for Implementation and MtSS
If inheritance is used for reuse by excluding some of the methods of the parent class, then this type
of inheritance is generally known as inheritance for implementation [70]. In this case, some methods
of the parent class are excluded in the child class public interface. The semantics of the inherited
methods are not modi ed. For example, class queue can be implemented using deque by excluding
the push2, pop2, and top2 methods of deque and allowing only push, pop, top, and empty methods.

31
Count
increment
decrement
reset
set_value
set_reset_value
get_value
get_reset_value

IntegerCount ASCII Count DateCount


increment increment increment
decrement decrement decrement
reset reset reset
set_value set_value set_value
set_reset_value set_reset_value set_reset_value
get_value get_value get_value
get_reset_value get_reset_value get_reset_value
asBase

Figure 3.2: Speci cation and Veri cation of Counter Design

Some new methods can be added in the child class. Thus inheritance for implementation promotes
reuse of previously developed code. Several languages such as C++ and CommonObjects support
for excluding methods of parent class in child class [45, 70].
The rule that checks the consistency between parent and child class remain similar to the one
described in section 3.1.1. The only di erence is that some of the parent methods are not inherited
and therefore these methods must not be considered in parent class regular expression when applying
the consistency rule.
3.1.4 Feasibility Evaluation
The practicality of the MtSS technique was evaluated by using it to specify two OO designs given
in [17]. In [17], authors provide a detailed OO design and program in SmallTalk and C++ for four
projects. We chose the Counter and ATM design projects for representing all the classes in each
design using MtSS technique.
In gure 3.2 the inheritance hierarchy of Count class is given. In this example, the authors have
used re nement inheritance. The IntegerCount class enhances the inherited class with a new method
asBase. All the child classes re ne the methods increment and decrement, but do not change the
protocol of them. The sequence speci cation of Count class is,
Methods ! Count  DataSetup  Operations   Count
DataSetup ! set value  set reset value
Operations ! (increment  decrement  reset)

32
In the above sequence speci cation, DataSetup methods can be invoked only once and once the
data is set up, all the Operations methods can be used. If the designer desires to allow initialization
methods to be invoked intermixing with other operation methods, then the speci cation must be
modi ed. But, the goal of the above speci cation is to explicitly specify the sequence relation that
exists between methods.
The IntegerCount class inherits all the methods from Count class and a new method asBase is
also added. The speci cation of IntegerCount is similar except that of Operations:
Methods ! Count  DataSetup  Operations   Count
DataSetup ! set value  set reset value
Operations ! (increment  decrement  reset  asBase)
Even though the speci cations of IntegerCount and Count can be veri ed visually, the consistency
rules are useful as a part of CASE tool used for OO analysis and design. The algorithm to verify
the consistency in sequence speci cation can be implemented as a part of a CASE tool that ensures
consistency every time an inheritance relation is created. The consistency rules are also bene cial
when an inheritance tree grows in depth.
The additional advantage of the above speci cation is that it helps to understand the interface
of a class. The sequence speci cation clearly speci es the sequencing information which is useful
during program development so that the class can be used correctly.

3.2 Multiple Interfaces and MtSS


OO paradigm promotes strict encapsulation of internal detail of objects from other objects by
restricting all the interactions only through supported methods. Methods of objects are invoked by
methods in other objects. Thus for each object there can exist a set of client objects. Each of the
client object may interact with the server object using only subset of the methods. Thus, if a server
object supports many client objects, the requirement of each of these clients vary. Therefore, it is
useful to provide access to only a subset of the methods of object to each of the client objects. Even
though an object de nes many external methods, all these methods are not universally available
to all the client objects. Thus, for each class, multiple interfaces exporting a subset of methods
providing restricted access can be de ned [29, 70].
Multiple interfaces are useful as they provide additional encapsulation to object structure. Sepa-
rate subinterfaces to di erent users facilitates understanding, maintenance, and proper use. Multiple
interfaces thus support the concept, separation of concern which is essential for understanding com-
plex software. Multiple subinterfaces provide a well guarded access control. The access control
interfaces are useful for providing debugging interface to each class so that some specialized users
such as debuggers can access the internal details of the object. Multiple interfaces also provide
support for implementing trusted users, and for implementing security levels and users in programs
such as operating systems [39].
An object may support multiple methods and only subset of these methods may be a part of a
subinterface to a client. Some of the methods can also be shared in more than one subinterfaces.
Because, each client's view of the server class is through the interface, the MtSS for each subinterface
de nes the proper use of the server class. Therefore, sequence speci cation of methods for each
subinterface is useful. Because, methods are shared across interfaces, the MtSS of these shared

33
methods must be consistent. In the following we model the multiple subinterfaces and de ne the
consistency rule that the sequence speci cation of all subinterfaces must follow.
3.2.1 C&C of MtSS with Multiple Interfaces
For a given class C , let, I1 ; : : : ; Ik be di erent subinterfaces the class supports. In the following we
de ne some more terms that are useful for de ning the rule.
De nition 3.8 Methods(Ii; C ): The Methods(Ii; C ) de nes a set of methods of class C that are
available to subinterface Ii . This is also denoted by i .
De nition 3.9 SeqSpec(Ii; C ): SeqSpec(Ii; C ) de nes the MtSS for the subinterface Ii of class C .
From the above de nitions we can write that [i i = Methods(C ). i.e. the union of all the
methods in each of the interface is equal to all the methods supported by a class C . The set of
methods, i \ j ; (i 6= j ) need not be a null set which means that subinterfaces may share several
methods. We model the sequence speci cation for each subinterface Ii by a regular expression
MtSSi.
Informally, the consistency rule is that the sequence speci cation between two subinterfaces that
share common methods must represent same method sequences containing the shared methods.
In the following we describe the consistency rule formally that each of the subinterface sequence
speci cation must satisfy.
Rule 3.5 Let I ; : : : ; Ik , be the subinterfaces of class C ,
1
MtSS ; : : : ; MtSSk be the corresponding sequence speci cation for each interface i,
1
NewMtSSi = -instantiate(MtSSi ; i ; (i \ j )), and
NewMtSSj = -instantiate(MtSSj ; j ; (i \ j )), then
8i;j^i6 j ; Language(MtSSi ) = Language(MtSSj )
=

In the above rule, for two interfaces Ii and Ij , MtSSi and MtSSj are the MtSS of the class.
NewMtSSi and NewMtSSj are the MtSS of Ii and Ij containing only those methods that are
shared between the interfaces. Then, the rule is that NewMtSSi and NewMtSSj must be equal.
Multiple interfaces: Example
Figure 3.3 shows the Account class having 3 sub-interfaces to classes Manager, Ocer, and Owner.
The Manager and Ocer classes share four common methods such as compInterest(), genReport(),
changeAddress(), and close(). The MtSS of these two interfaces must agree on the inter-method
relation of these four methods. This can be veri ed using the above rule. Further, when new methods
are added to one or more interfaces, then the rule can be reapplied to verify the consistency of the
MtSS of each of the interfaces after adding the method. When classes contain several methods and
support a lot of interfaces, the consistency checking of the MtSS will be very useful.

3.3 Algorithm for Consistency Checking


All the consistency rules speci ed in this paper can be implemented using one uniform consistency
checking algorithm. The MtSS for each of the class can be represented using regular expression

34
Account Manager

Create
CompInterest interface
GenReport
ChangeAddress Officer
Close
Delete
Open
Deposit
Withdraw Owner
Balance

Figure 3.3: Example Illustrating Multiple Interfaces of Account Class

syntax. A regular expression de nes a well-de ned regular set that contains all possible strings that
can be generated from the regular expression. All the consistency checking rules use the equality
boolean operator to verify the consistency between two regular expressions. The equality between
two regular expressions can be expressed as a decision algorithm on the regular sets of each these
regular expressions.
In [34], an ecient algorithm is presented for verifying whether one regular expression is the same
as the other. Each regular expression de nes a Finite Automata (FA). A FA accepts a set of strings
and all the acceptable strings form the language de ned by the FA. If L1 and L2 are the languages
represented by two regular expressions, then the two regular expressions are equal if L1 = L2. One
can verify this, by constructing a new FA D1 satisfying L1  L2 ( is the exclusive-or operator) and
verifying whether D1 accepts any non-empty string. If D1 represents an empty regular set, then
L1 = L2. Ecient methods and proofs for constructing intersection and complement operators are
provided in [34].

3.4 C&C of MgSS


In the last section, we have discussed about C&C of MtSS in the presence of inheritance and multiple
interfaces. In this section we discuss about various C&C rules associated with MgSS.
MgSS is speci ed for each method in a class that interacts with other classes. MgSS for each of
the method captures the causal order in which messages are sent out to di erent objects. To specify
the MgSS, we use the same formalism as of MtSS.
MtSS and MgSS together describe how a set of messages ow through the system. MtSS and
MgSS compliment each other, one providing how methods can be invoked at a class and other
describing how each method sends out messages. In the following we give various rules that MtSS
and MgSS together must satisfy.
Rule 3.6 Let, C1:::(k;1) be proper child classes of Ck. For a method m1 of a class Ck , the MgSS of
m1 remains the same in classes C1:::(k;1) if,

35
1) m1 is inherited under specialization inheritance, or
2) m1 is inherited under re nement inheritance and m1 is not modi ed, or
3) m1 is inherited under reuse inheritance.
Thus the MgSS of a method in the parent class remains the same under child class under various
inheritance mechanisms if the method is not modi ed in the child class.
In the following we provide a rule that checks the consistency between the MtSS of a class and
MgSS of a method that sends out messages to the class.
Rule 3.7 Let C and C be two classes which are related as client and server respectively. Let
1 2
MtSS2 be the MtSS of the class C2. Let MgSS1 be the MgSS of a method m1 of the class C1. If
the method m1 of C1 sends out messages m2 and m3 to class C2 , then the relation between m2 and
m3 in MgSS1 must be same as in MtSS2.
In the above rule, we are assuming that message to method binding is unique and is one-to-one.
Thus, the MgSS and MtSS involving two methods of the same class must be same. The above rule
is valid under various inheritance schemes when the methods involved are not modi ed.
When a cluster of classes are all related and each class sends messages to several other classes,
the consistency of MgSS and MtSS of various classes is important. In the following we provide such
a rule.
Rule 3.8 Let C1 , C2 , and C3 be three classes where methods in classes C1 and C2 send messages
to class C3 . Let method m1 of class C1 send message m3 to class C3. Let method m2 of class C2
send message m4 to class C3 . If in the MtSS of class C3, methods m3 and m4 are causally related
as m3Rm4, then the same causal relationship must hold between the methods m1 and m2 .
In the above rule, two methods of di erent classes can be imposed with a causal order based on
the way they send messages to a common class. If there is any discrepancy in the causal relationship,
then there is inconsistency.

36
Chapter 4

C&C of Implementation
In OO software engineering life-cycle, design speci cations are used in implementing the nal pro-
gram. Since the implementation from design is a manual process, a nal program might contain
many inconsistencies and incompletenesses. As we have discussed in the previous chapters, the
MtSS of a class speci es the correct sequence in which messages can be sent to instances of the class.
Similarly, the MgSS speci es the causal order in which messages are sent out by each of the methods.
But, in implementation, the program may contain method and message invocation sequences which
are inconsistent with the MtSS and MgSS of the classes. In this chapter, we brie y discuss how one
can use MtSS and MgSS along with the control- ow analysis of the program to identify the sequence
related inconsistencies.
A MtSS associated with an object speci es sequence in which its methods can be invoked. Even
though a class supports many methods, in practice, only subset of the methods might be invoked
at the class instances. The sequence in which the methods are invoked at each object is called
use sequence with respect to that object. For a given OO program, once all the use sequences are
determined by analyzing the program, then the use sequences can be compared against the MtSS of
the corresponding classes to determine any inconsistencies.
Thus the goal of dependency analysis is to determine the actual sequence in which the methods
of an object are invoked. To determine the use sequences at each object, control ow analysis [31, 44]
of the OO program is essential. Speci cally, for a given OO program and a starting method, if a
method invocation tree can be generated, then one can generate use sequences from the the method
invocation tree. Each of the node in the method invocation tree contains the object, its class, and
the method invoked.
Control ow analysis of the procedural programs has been well studied. However, the control ow
analysis for OO programs may require modi cations to identify all possible method use sequences
for each object. The presence of pointers, polymorphism, dynamic typing, and dynamic binding
complicates the control ow analysis. In [44], authors have discussed about generating cross-reference
information about method-message pairs in C++.
Thus, MtSS of a class can be used for verifying the consistency of the implementation of the class
against the speci cation. However, this veri cation depends on the result of control ow analysis in
identifying all the use sequences. In this chapter, we stress on veri cation aspects of the program
rather than control ow analysis. In gure 4.1, an Account object is shown with three other client
objects sending messages. The numbers on the arc correspond to sequence in which the methods

37
Start
Client A 1
2
3
4
Open
Deposit foo

Account Close 5 Client B


Object

Withdraw 6
bar
7

Client C

Figure 4.1: An example for illustrating veri cation of implementation against the speci cation.

are expected to execute. Control ow analysis can be used for determining such sequences. From
the gure we can see that a sequence of methods the Account can execute is,
(open  deposit  close  withdraw)
This sequence does not belong to the SafeSeq(Account) as withdraw() method is invoked after the
close() method. Thus, using MtSS and static control ow analysis of OO program one can identify
all such invalid sequences for each object. Each such invalid method sequence may be a potential
fault.

4.1 Run-time Veri cation System


The static control ow analysis of OO program may not be able to identify all possible use sequences
due to the presence of dynamic binding, polymorphism, dynamic typing, and pointer data structures.
For dynamically typed languages such as SmallTalk, it may be impossible to derive all the use
sequences from the program. If all use sequences are not identi ed and compared for its compliance
against the MtSS, then there may be some inconsistencies left out in the program. For safety-
critical systems [53] it may be necessary to identify all such inconsistencies in using the methods of
an object, either at compile time or during execution. The run-time veri cation system proposed in
this chapter helps in identifying such incorrect method invocations.
During execution, each object receives a message from client objects. With response to each
message, the object executes a corresponding method. The message-method binding can take place
during execution time (dynamic binding). Thus, at each object one can monitor the set of messages
the object receives and the sequence in which the object invokes its methods. The run-time veri -
cation system monitors all the methods invoked at an object and compares with the MtSS of the
corresponding class. Thus, each object maintains an access pointer to the MtSS of the corresponding

38
Class Data Structure
Account-Object-1
Method Dictionary
State
Name Executable Sequence
Dictionary verifier
Deposit - Pointer
Specific.
Withdraw - Pointer
... ... Method
Invocation
Account-Object-2
Sequence Specification
State
Sequence
. . . . .)
Open Deposit (
Dictionary
verifier
Pointer
Specific.
Pointer

Figure 4.2: Data structure diagram for implementing run-time veri cation system

class. For each invocation of the method, the veri cation system checks for the sequence consistency
with respect to the stored sequence speci cation. If the method invoked is not compliant with the
speci cation, then an exception is raised and control is transferred to an exception handler.
The run-time veri cation system determines sequence correctness by checking the method se-
quence with the regular de nition of the MtSS. To specify the causal order among methods, MtSS
uses regular expression language operators such as '', 'j', '?', and '+'. The veri cation of use se-
quences with respect to the MtSS is similarly to checking whether a string is part of a regular
de nition. This algorithm to check whether a string is part of a regular set is well known [34] and
can be easily implemented.
Objects when they are created during run-time, maintain link to its class. The class maintains
the method dictionary for all its instances. The method dictionary contains the name of the method
and the address of the executable binary code. Thus, all the objects of a class share the method
dictionary.
In gure 4.2 a data structure diagram is shown that can implement a run-time veri cation system.
The MtSS of the class is placed along with the method dictionary so that all instances of the class
can have access to the same MtSS. Each object instantiation stores space for the instance variable,
pointer to the method dictionary and a pointer to the MtSS. Further, at each object a sequence
veri er code is kept. All the method invocations are processed rst by the sequence veri er. The
sequence veri er checks each invoked method with the MtSS for correctness. the sequence speci er
keeps track of the methods received so far at each object in its internal state. If a invoked method
is a out-of-sequence method then an exception is raised, otherwise, the method code is accessed
from the method dictionary and is executed. The above run-time veri cation system can be used in

39
SmallTalk implementations as its run-time structure is open for modi cation.

40
Chapter 5

Data Flow Anomaly Detection in


Classes
5.1 Introduction
In recent years object-oriented paradigm is gaining acceptance for developing complex software. Even
though the importance of veri cation and validation is known, it has commanded little attention
in OO paradigm. In this chapter, we propose a technique for identifying the data ow anomalies
associated with the methods of a class. Even though the techniques to identify data ow anomalies
in procedural programs are well known, they are not directly applicable in OO paradigm. We use
MtSS in conjunction with the conventional data ow anomaly detection techniques to identify the
data ow anomalies in classes. The proposed technique is applicable under di erent inheritance
mechanisms.
Data ow analysis used in compiler optimizations [1], has been used for identifying data ow
anomalies in procedural programs [26, 35, 36]. A data ow anomaly is present when the pattern
of variable usage is abnormal in the sense that the usage of variable violates the principles of
computation [26]. The presence of data ow anomalies indicate a possible programming error and
thus a program if executed may produce incorrect results. From the fault statistics published in [6]
it is reported that at least 15% of the data related faults (22% of the total faults) are due to di erent
types of data ow anomalies. A program containing data ow anomalies is less reliable than the one
which does not contain any data ow anomalies.
OO paradigm supports the development of reusable classes [12, 37]. Reusable classes are well
speci ed and general enough so that they can be used in variety of applications. A class de nes a set
of instance and class variables. These variables are used and modi ed by the methods de ned in the
class. The variables are global to the methods de ned in a class. Thus methods share a set of instance
variables and improper usage in variable access can lead to potential data ow anomalies. Reusable
classes clearly specify the public methods that it supports, however it does not impose any sequence
in which the methods can be invoked. As there is no causal relationship de ned between the methods,
it is not possible to determine the causal order in which the methods are executed by just analyzing
the reusable classes. Since, data ow anomaly detection technique depends on a well de ned control
ow among the methods, the method execution sequence is necessary for identifying the data ow

41
anomalies in classes. Therefore, the conventional data ow anomaly detection techniques alone
cannot be used to determine the anomalies that are present across the methods.
In this chapter, we use MtSS that represents the causal relationship that exists between the
methods of a class. The MtSS of a class documents the correct order in which the methods of
the class can be invoked by methods in other client classes. Here, we use MtSS along with the
conventional data ow analysis technique to identify the data ow anomalies in variable usage.
In section 5.2 we discuss conventional techniques for identifying the data ow anomalies in
procedural programs. In section 5.3 we discuss about data ow anomalies in classes. We then
discuss brie y about MtSS for capturing the causal relation among methods. In this section, we
then discuss the technique of data ow anomaly detection in classes with an example. In section 5.4
we discuss about data ow anomalies in the presence of inheritance. Then, we conclude this chapter
and list out possible future work.
5.1.1 Related Research
Data ow anomaly detection in programs written using procedural languages such as FORTRAN
and C has been studied in the past [26, 35, 33, 36]. In [26], authors de ne the data ow anomaly
problem and provide algorithms adapted from data ow analysis techniques for identifying the data
ow anomalies. The representation of data ow accesses as path expressions and then checking the
path expressions for a possible anomaly detection is presented in [26, 35]. In [36], authors identify
a aw in the algorithm given in [26] and provide an ecient and easy to implement algorithm
for identifying the data ow anomalies. Recently, [72] discusses various issues related to data ow
anomaly testing at various levels in OO programs. Several issues related to V&V and maintenance of
object-oriented programs are given in [68]. Issues related to adequate testing of classes is considered
in detail in [62]. In this paper, we provide a technique for identifying the data ow anomalies in
classes. We use MtSS of class as well as the conventional technique for representing the data ow
accesses as path expressions and checking for the data ow anomaly.

5.2 Data ow Anomalies


Data ow anomalies are those anomalies related to the accessing and updating of data items in a
program. Data ow anomalies occur during the implementation phase of a software due to common
programming errors such as misspelling, name confusion, deletion of statements, incorrect copying
a portion of the program from some other program, and similar errors. The presence of data ow
anomaly in a program implies that the execution may produce incorrect results only if the anomalous
portion of the software gets executed. Thus, a software with data ow anomaly is less reliable and
susceptible to failures than the software without any data ow anomalies. Therefore, it is essential
to detect all types of data ow anomalies in a program and eliminate them. We use the following
example to describe the data ow anomaly model.
Let us consider the method deposit() of a class Account written in C++ (see gure 5.1). In this
example, data ow anomalies are introduced for illustration purpose. We use this example while
discussing the data ow anomaly model also.

42
1 Account:: deposit (int acct_no, Amount amt)
2 {
3 int err; Amount temp;
4 temp = amt;
5 if (acct_no == account_number)
6 balance = balance + amt;
7 else {
8 err = err + 1; // data flow anomaly
9 err = error.get_error_sequence();
10 display (err);
11 }
12 }

Figure 5.1: Example to illustrate the data ow anomaly model and detection

5.2.1 Data ow Anomaly Model


In a program the data objects are initially declared and then they are referenced and de ned until
the program terminates. In the following, we de ne four operations that are commonly performed
on the data objects or variables.
1. De ne(d): A data variable is de ned when its value is changed. When a data variable appears
on the left hand side of an assignment statement, the variable is said to be de ned by that
statement. In the example in gure 5.1, the variable temp is de ned in line four as its value is
updated.
2. Reference(r): A data variable is said to be referenced when its value is used without modifying
the contents. In the above example, the variable amt is referenced as its value is accessed in
line 4.
3. Kill(k): A variable is said to be killed when its contents are no more available or when its
contents are no longer known. All the variables are assumed to be killed before they have
any initialization. Once the program terminates, all the variables are considered killed. For
example, the variables err, temp, acct no, and amt are killed in line 12, as their values are not
accessible outside the method deposit().
4. Null(1): An action on a variable is de ned as null when none of the above three actions take
place. For example, the variable err has null action in line 4, as it is not referenced, modi ed,
or killed.
Depending on Di erent combinations of r, d, k, and 1 operations on a variable, data ow anomaly
occurs. The data ow anomalies are represented by two letter combinations. Di erent data ow
anomalies are:
1. dk: This combination may be a fault as a variable is de ned and killed without being used.
In the above example, the variable temp is de ned in line 4 and is killed in line 12 without an
intermediate use.

43
2. dd: This combination may be harmless but suspicious as the variable is de ned twice without
an in between use. In the above example, in line 8 and 9, the variable err is de ned twice
without an intermediate use indicating a possibility of a fault.
3. kr: This combination is a fault as a variable whose value is not de ned, is being referenced.
In the above example, the variable err in line 8 is referenced before its value is initialized.
5.2.2 Anomaly Detection in Conventional Programs
The data ow anomaly detection techniques described in [26, 36] are based on the static analysis
of the control ow of a program. The techniques initially represent the program statements as a
control ow graph and then the graph is analyzed for various data ow anomalies. The techniques
identify the anomalies in linear time.
A sequence of operations that take place on a variable along a control ow path can be represented
using a sequence of r's, d's, k's, and 1's. Such an expression is called a path expression. The data
ow analysis technique initially constructs a path expression for each variable at every node and
then the path expression is analyzed for the anomalies. The data ow anomalies can be expressed
in terms of path expressions. For example, a path expression of the form pkrp0 corresponds to an
anomaly of referencing an unde ned variable where, p and p0 stand for arbitrary path expressions.
Similarly, the path expressions corresponding to other anomalies are pdkp0 and pkrp0. For example,
in gure 5.1, the path expression for variable err in line 8 is pkrdp0. i.e. the variable err is accessed
before it is initialized and therefore there is an anomaly in usage of the variable err in line 8. In
the following we brie y describe the data ow anomaly detection technique [26, 36] that use path
expressions.
Let, G(N; E; n0 ; ne ) represent a ow graph where N is the set of nodes, E is the set of edges, n0
is the unique entry node 2 N and ne is the unique exit node. The nodes in G represents the program
statements, and edges represent the control paths among the statements. In G a simple node is used
to represent a simple statement and a calling node is used to represent a subroutine or function call.
We use the term token to represent variables. Let, P (! n; ), P (n; ), and P (n !; )represent path
expressions for a variable on paths entering the node n, at node n and on paths leaving node n.
For example, a ow graph corresponding to the example given in gure 5.1 is shown in gure 5.2.
The token set is f acct no, amt, err, temp, balance, and account number g. In the ow graph, the
node numbers correspond to the line numbers of the gure 5.1. Di erent path expressions associated
with the variable err before, at, and after the node 8 are,
P (! 8; err) = k (5.2.1)
P (8; err) = rd (5.2.2)
P (8 !; err) = drk (5.2.3)
If the last action on the variable on all paths before entering the node n is k, and the rst
action on at node n is r, then the path expression for on that path including n would be of the
form pkrp0 where p and p0 stands for arbitrary path expressions. i.e., if
P (! n; ) P (n; ) = pkrp0
then there exists a data ow anomaly in the variable usage. For example, combining the equations
5.2.1 and 5.2.2, the variable err has a path expression pkrdp0, thus having an anomaly in the variable
err usage. A data ow anomaly on all paths through node n exists if any of the following is satis ed:

44
n0

7 6

10

ne

Figure 5.2: Flow graph corresponding to the example given in gure 5.1

45
P (! n; )P (n; ) = pxyp0 (5.2.4)
P (n; )P (n !; ) = pxyp0 (5.2.5)
P (! n; )P (n; )P (n !; ) = pxyp0 (5.2.6)
where xy 2 fkr; dd; dkg.
It is possible P (! n; )may be of the form p0 + px indicating that on certain paths entering node
n, the last action is not x. On such paths, there may not be any anomalies. In general, if
P (! n; )P (n; ) = pxyp0 + p00 (5.2.7)
P (n; )P (n !; ) = pxyp + p 0 00 (5.2.8)
P (! n; )P (n; )P (n !; ) = pxyp + p 0 00 (5.2.9)
where xy 2 fkr; dd; dkg, there exists at least one path entering n with an anomaly on variable .
From the above, we see that the data ow anomalies can be detected by analyzing the path
expressions at node n and on paths leaving and entering node n. If the node n is a function or
procedure invocation, then all the path expressions in the called subprogram must be computed
before computing the path expressions of the caller1. Thus, to determine the data ow anomalies in
a program, one has to compute path expressions at each node of the program and then analyze the
path expressions for basic data ow anomalies.
The path expressions at each node of a program can be eciently computed using the data
ow analysis and code optimization algorithms of LIVE, AVAIL, and REACH. These algorithms
are well studied and known in compiler literature [1]. The paper from [26] describes a technique
for determining the path expressions using these algorithms. An improved and ecient algorithm
is given in [36] for computing the path expressions. As the main focus of this paper is to use their
results for nding the data ow anomalies in OO programs, we will not be discussing the details of
the algorithm.

5.3 Data Flow Anomaly in Classes


OO paradigm advocates on constructing reusable classes and using them as components by assem-
bling them. These reusable classes describe several interface methods that are available to other
classes to send messages. A method de ned in a class share a set of class and instance variables
that are global to the methods of the class. The methods refer and update these variables and
usually hold other objects in them. Further, methods itself may have several local variables that
they de ne and refer. Thus, the data variables in a class are class variables, instance variables,
and local variables within methods. Inappropriate accessing of these di erent variables by methods
can result in data ow anomalies. The anomalies associated with the local variables of a method
can be easily identi ed using the conventional techniques described in section 5.2. However, the
conventional techniques are not directly applicable to identify the data ow anomalies associated
with the class and instance variables de ned in a class. In the following we illustrate this using an
example.
1 This approach known as segmentation approach can handle only acyclic call graphs and thus recursive programs
cannot be handled.

46
Data ow anomaly detection: Example
Let us consider a simple bank account class with three instance variables account no, customer name,
and balance. The interface methods are, open () used for opening an account, close() for closing an
account, deposit() for depositing the money, and withdraw () for removing the money from an account.
A simple C++ code that implements the above is given below.
class Account {
public:
void open (int acct_no, name cust_name);
void deposit (int acct_no, amount amt);
void withdraw (int acct_no, amount amt);
void close (int acct_no, name *cust_name);
...
protected:
amount balance;
name customer_name [64];
int account_no;
...
}
void Account::open (int acct_no, name cust_name)
{
account_no = acct_no;
customer_name = cust_name;
}
void Account::deposit (int acct_no, amount amt)
{
if (account_no == acct_no)
balance = balance + amt;
else error(acct_no);
}
void Account::withdraw (int acct_no, amount amt)
{
if (account_no == acct_no){
if (amt <= balance){
balance = balance - amt;
}else ...
}
}
void Account:: close (int acct_no, name cust_name)
{
if ((account_no != acct_no) !! (cust_name != customer_name))
error(acct_no, cust_name);
else ...
}

47
In the above example, the methods refer and modify the instance variables to perform their task.
To identify the data ow anomalies associated with these variables, we need to analyze the methods.
Individual analysis of these methods result in detection of incorrect anomalies. For example, in the
method deposit() the instance variable account no is referred before its value is set and this may
be identi ed as an anomaly even though it is not an anomaly as the method open() initializes the
variable and gets invoked before the method deposit(). The incorrect anomaly detection is due to
the absence of well-de ned control ow between the methods. Even if the method open() did not
initialize the variable account no, the analysis technique cannot identify the existence of anomaly.
Thus, we need to know the dependency among the methods before analyzing them for the anomaly.
In this chapter, we use the MtSS to specify the causal relationship between the methods and use
this speci cation for identifying the data ow anomalies. In the following we describe how the MtSS
can be used for anomaly detection in classes.
5.3.1 Data Flow Anomaly Detection in Classes
In this chapter we discuss only about the data ow anomalies associated with the instance variables.
The anomalies associated with the local variables within a method can be determined by analyzing
the methods using conventional techniques. Here, we propose a three step technique for identifying
the data ow anomalies associated with the instance variables of a class. The steps are,
1. Model all the causal relationship between the methods of a class using MtSS described in
chapter 2. The sequence speci cation can be derived from state based design, object diagram,
or interaction diagram using the technique described in the section 2.2.
2. Translate the MtSS into a control ow graph. The translation process maps each method to a
node and regular expression operators as edges between the nodes. This process is described
in the next section.
3. Apply the conventional technique that determines the path expressions at all the nodes on the
control ow graph and evaluates them to determine the data ow anomalies as explained in
section 5.2. As the constructed control ow graph is similar to a function invoking a set of
other functions, the conventional technique can determine the anomalies.
In the following we describe the technique for converting a MtSS to control ow graph suitable
for conventional data ow anomaly detection techniques.
Constructing control ow graph from MtSS
The MtSS uses the regular expression formalism to represent the causal relationship between the
methods. The regular expression operators that can be used in MtSS are , ?, j, and +. These
operators are used to link the methods in a causal relation. In the following, we describe the method
of converting regular expression operators to corresponding control ow graphs.
A  B - The regular expression operator '' represents a sequence relation between the methods A and
B in a sequence speci cation. i.e. the method A is executed before the method B is executed.
This regular expression is converted to a control ow graph consisting of nodes A and B with
a directed edge between them.

48
Regular Regular
Control flow graph Control flow graph
Expression Expression

n3
A
A B
A.B
A*

A
n4

n1 n5
A
A|B A B A+

A
n2 n6

Figure 5.3: Regular Expression to Control Flow Graph Conversion.

A j B - The regular expression operator 'j' represents an 'OR' operator between two methods in a
sequence speci cation indicating that either method A is executed or B is executed but not
both. This regular expression is converted to a control ow graph with 2 parallel directed
paths between two dummy nodes n1 and n2 with node A and B in each of the path. The
nodes n1 and n2 does not read or modify any variables.
A? - The regular expression operator '?' indicates that a method can be repeatedly invoked (possibly
0 times). In [35] it has been shown that for data ow analysis purposes for every 'A?' in a
regular expression, one can substitute with '(1 j (A  A))' without any changes in the number
of data ow anomalies. While constructing the control ow graph, this theorem is used and
the equivalent control ow graph for '?' is shown in gure 5.3.
A+ - The regular expression operator '+' indicates that a method can be executed repeatedly but at
least one time. Extending the theorem from [35], the regular expression 'A+' can be converted
to '(A j (A  A))' for data ow analysis purposes. The control ow graph equivalent to 'A+' is
shown in gure 5.3.
A sequence speci cation can contain several methods connected through these various regular
expression operators. The above technique of converting to control ow graph is repeatedly applied.
In the control ow graph adjacent dummy nodes are reduced to one dummy node. In gure 5.3, the
control ow graphs corresponding to di erent basic regular expressions are shown.

49
Example
In this section, we illustrate the three step technique of determining the data ow anomalies in a
class using an example. We chose the Account class described in section 5.3 for determining the
anomalies.
STEP1: Method sequence speci cation
The Account class consists of four methods open, close, deposit, and withdraw. The expected behavior
of the methods is that the method open must be invoked before invoking either deposit and withdraw
methods, and close method is the last one that can be invoked. The method sequence speci cation
corresponding to this behavior of the Account class is,

Methods ) open  (deposit  (depositjwithdraw)?)  close (5.3.10)


) open  deposit  (1j(depositjwithdraw) )  close
2
(5.3.11)
) open  deposit  (1j(deposit  deposit)j(deposit  withdraw)j
(withdraw  deposit)j(withdraw  deposit))  close (5.3.12)
The equation 5.3.10 corresponds to the sequence speci cation that can be derived from the design
or a user speci ed one. Using the Huang's theorem [35], in equation 5.3.11, the regular expression
'?' operator is reduced. In equation 5.3.12, the exponentiation is expanded using the equation
(A j B )2 = (A  A) j (A  B ) j (B  A) j (B  B ). We use the equation 5.3.12 for converting it to control
ow graph.
STEP2: Control ow graph construction
The control ow graph is constructed from the equation 5.3.12. We use the same technique as
described in the gure 5.3. The sequence speci cation in equation 5.3.12 contains only '' and 'j' op-
erator. The '' operators are constructed to a directed edge between its preceding and consequenting
method nodes. The expression within the huge brackets in the equation 5.3.12 is converted to ve
parallel paths between two dummy nodes n1 and n2 . The control ow graph corresponding to the
equation 5.3.12 is shown in the gure 5.4.
STEP3: Identify data ow anomalies
To identify the data ow anomalies, one has to initially determine the path expressions at each node
in the control ow graph. The nodes in the control ow graph corresponds to various methods of
the class. The code corresponding to class Account is given in section 5.3 and we will be using the
same to determine path expressions.
The path expressions corresponding to the methods of the class Account (see the program seg-
ments in section 5.3) with respect to the instance variable balance are given below.

P (! open; balance) = k (5.3.13)


P (open; balance) = 1 (5.3.14)

50
open

deposit

n1

deposit withdraw
deposit
withdraw

withdraw withdraw
deposit

deposit

n2

close

Figure 5.4: Control Flow Graph representation of the sequence speci cation of \Account" Class.

P (deposit; balance) = rd + 1 (5.3.15)


P (withdraw; balance) = rrd + r + 1 (5.3.16)
P (close; balance) = 1 (5.3.17)
In equation 5.3.13, because all the variables are killed before the program starts, the path ex-
pression with respect to token balance is k. Because the method open does not read or update this
variable, the path expression in equation 5.3.14 is 1 which indicates that no operations are performed
on this variable. In the method deposit, the instance variable balance is read and then updated in
one of the paths and therefore in equation 5.3.15 the path expression is rd + 1. Similarly, the path
expressions for the method withdraw and close are computed and are given in equation 5.3.16 and
5.3.17 respectively.
Once the path expressions for the nodes in the control ow graph are identi ed, then they are
analyzed for various data ow anomalies. As discussed in section 5.2, the two letter combinations of
data access dk, dd, and kr correspond to data ow anomalies. Continuing with our example, here
we analyze one of the path of the control ow graph shown in gure 5.4. Let us consider the path,
open ! deposit ! n1 ! withdraw ! withdraw ! close (5.3.18)
The path expressions for the variable balance at the rst deposit node in the path 5.3.18 has the
path expressions,
P (! deposit; balance) = k (5.3.19)
P (deposit; balance) = rd + 1 (5.3.20)

51
where, the equation 5.3.19 corresponds to just before invoking the method deposit and equa-
tion 5.3.20 corresponds to the path expressions in the method deposit. Combining the above two
path expression we get:
P (! deposit; balance)P (deposit; balance) = k(rd + 1) (5.3.21)
Expanding the parenthesis in the path expression 5.3.21, we get:
P (! deposit; balance)P (deposit; balance) = krd + k (5.3.22)
In equation 5.3.22 we see the pattern kr corresponding to a data ow anomaly. All the data ow
anomalies that appear in that path expression is underlined. This data ow anomalys is with respect
to usage of the instance variable balance in the method deposit. If we analyze the program given in
section 5.2, we see that the instance variable balance is not initialized in the method open. However,
while writing the program for the method deposit it was assumed that the instance variable balance
was initialized in the method open. This fault is clearly identi ed by the technique we have discussed
in this chapter. However, the conventional techniques, if applied directly, cannot determine such
data ow anomalies.

5.4 Inheritance and Data Flow Anomalies


In inheritance, a child class inherits both the operations and implementations de ned in parent
classes. The child class, in addition to inherited methods, can further enhance the class with ad-
ditional operations or change the implementation of inherited methods [70, 51, 42]. Inheritance
can be used for specialization, re nement as well as for implementation (reuse) purposes [51, 70].
If inheritance is used for specialization, then the child class conforms to the semantics of all the
inherited methods from the parent class. The child class may extend the class with additional meth-
ods. Thus, the child class does not modify the semantics of the inherited methods and obeys the
inherited methods protocol. In Ei el, the specialization inheritance can be ensured with the help of
pre-conditions and post-conditions for the parent class methods [51]. If inheritance is used for re-
nement of the parent class, then the child class may modify the semantics of the inherited methods.
Thus, the inherited methods are re ned or modi ed and the behavior of child class method may be
di erent from the behavior of the corresponding method in the parent class. If inheritance is used
for implementation, then the child class may not inherit all the methods from the parent class, and
may modify the semantics of the inherited methods [70, 42].
Inheritance is used commonly in OO systems. Further, the depth of inheritance hierarchy can
be deep for large systems. The child classes in the inheritance hierarchy usually specialize or re ne
the parent classes. The rst issue here is to determine in what order the classes in the inheritance
hierarchy must be subjected for data ow testing. The second issue is, if the parent classes have
been subjected to extensive data ow anomaly testing and are free of data ow anomalies, then
how one can minimize the data ow anomaly testing of child classes. One brute-force approach is
to subject all the methods in every inherited class to data ow anomaly testing. In this chapter we
discuss the various conditions under which all the inherited methods need not be subjected to data
ow anomaly testing.
In an inheritance hierarchy, the classes are chosen for data ow testing in breadth rst order
from the root. Once the methods in parent classes are tested, then the methods in the child classes

52
SequenceableCollection

String Text Array LinkedList OrderedCollection

Figure 5.5: Partial inheritance hierarchy for SequenceableCollection class in Smalltalk

are subjected to data ow anomaly testing. For example, in gure 5.5, the breadth rst search
of the inheritance hierarchy would give SequenceableCollection, String, Text, Array, LinkedList, and
OrderedCollection. This is the order in which the classes must be subjected for data ow anomaly
testing. In the following we give de nitions that we use while discussing this section.
De nition 5.1 NewMethods(Ck): A set of methods that are newly added in class Ck and are not
inherited from the parent classes of Ck .
De nition 5.2 InhMethods(Ck; Ci ): A set of methods of class Ck that are inherited from class Ci
6 Ci. Let IM (Ck) be the set of methods that are inherited from all the parent classes of Ck .
and Ck =
De nition 5.3 Vn (C ): A set of instance variables that are newly introduced in class C .
De nition 5.4 Vo (C ): A set of all the instance variables that are de ned in all the parent classes
of class C .
De nition 5.5 ReachingMethods(M; CK ): A set of all the methods in class Ck that are reachable
from the method M in the control ow graph derived from the sequence speci cation of all the methods
in class Ck .

5.4.1 Specialization Inheritance and Anomaly Detection


In specialization inheritance the child class can add new methods, in addition to all the inherited
methods from the parent classes. However, the child class inherits all the public methods of the
parent class and does not modify them. Let, class Ck be a proper child class of C1 : : : Ck;1. In class
Ck , the Methods(Ck) can be split into NewMethods(Ck) and IM (Ck ).
Data ow anomaly testing with respect to Vn (Ck)
Because all the inherited methods IM (Ck ) of the class Ck does not use or modify the new instance
variables Vn (Ck), they need not be considered for data ow anomaly detection with respect to new

53
Account Methods: open, deposit, withdraw, close

Checking Account New Methods: balance, report

Figure 5.6: Example for Specialization Inheritance with two new methods

variables. So, only the new methods, NewMethods(Ck) need to be considered for data ow anomaly
detection.
Further, if the methods NewMethods(Ck) only reference a variable v 2 Vn (Ck) and do not
modify the data, then the methods need not be tested for anomaly detection with respect to v.
Data ow anomaly testing with respect to Vo(Ck )
The methods NewMethods(Ck) are the newly introduced methods that might use or modify the
instance variables Vo (Ck). If all the methods in NewMethods(Ck) only refer to the variables in
Vo (Ck) without modifying them, then these methods including the one that are inherited need
not be considered for data ow anomaly detection with respect to these variables. However, if
they do modify or update the variables, then the method sequence speci cation consisting of only
NewMethods(Ck) and the ReachingMethods(NewMethods(Ck)) methods need to be considered
for data ow anomaly detection.
Example
We provide an example to illustrate the data ow anomaly detection with respect to specialization
inheritance. In gure 5.6, the child class CheckingAccount specializes the parent class Account by
inheriting all the methods from the parent class. Further, the class CheckingAccount adds two new
methods Balance and Report. A new instance variable report string is also added.
In the following we give the code corresponding to the implementation of the class CheckingAc-
count in C++.
class CheckingAccount :public Account {
public:
...
amount balance (int acct_no);
void report (int acct_no);
...
protected:

54
char report_string[255];
...
}
amount CheckingAccount::balance (int acct_no)
{
if (account_no == acct_no){
return (balance);
}
else
error(acct_no);
}
char *CheckingAccount::report (int acct_no)
{
char * temp;
if (account_no == acct_no){
sprintf(temp, ``The balance in account %d on %s is %f\n'',
acct_no, today(), self.balance(acct_no));
strcpy(report_string, temp);
return (report_string);
}
else
error(acct_no);
}

In the following we give the methods that are inherited and new, as well as the new instance
variables and the ones that are from parent classes with respect to the example.

NewMethods(CheckingAccount) = fBalance; Reportg


IM (CheckingAccount) = fOpen; Deposit; Withdraw; Closeg
Vn (CheckingAccount) = freport stringg
Vo (CheckingAccount) = fbalance; account no; customer nameg
In the above example, the methods balance and report does not update any of the instance
variables de ned in its parent class (i.e. Account class) and they only refer to them. So, with respect
to all the instance variables Vo (CheckingAccount) one need not do any data ow anomaly detection
in the child class.
The method report modi es the new instance variable report string. With respect to new instance
variables (Vo (CheckingAccount)) only one of the new method refers to it and therefore only the
method Report needs to be tested for data ow anomaly detection.
5.4.2 Re nement Inheritance and Anomaly Detection
In re nement inheritance, the child class modi es the semantics of some of the inherited methods
from the parent classes. The modi cation in the inherited methods can be either in the method
protocol (also known as method signature) or behavior. The two corresponding methods in the

55
parent and child class that are related through inheritance, thus may produce di erent results for
the same set of inputs.
In re nement inheritance, the inherited methods are modi ed in its semantics. Further, the
child class may introduce new instance variables. The data ow anomaly testing with respect to
the new instance variables and those variables that are de ned in parent classes, is similar to the
one described in the previous section. i.e. For new instance variables, only those methods that are
re ned are considered. Further, if all the re ned methods only refer the instance variables, then
there is no need to subject any methods in the child class for data ow anomaly testing. For those
instance variables that are inherited from parent classes, the testing technique remain the same as
described in the previous section.
5.4.3 Implementation Inheritance and Anomaly Detection
If inheritance is used for reuse by excluding some of the methods of a previously de ned class, then
this type of inheritance is generally known as inheritance for implementation [70]. In this case, some
methods of the parent class are excluded in the child class public interface. The semantics of the
inherited methods are not modi ed. For example, class queue can be implemented using deque by
excluding the push2, pop2, and top2 methods of deque and allowing only push, pop, top, and empty
methods. Some new methods can be added in the child class. Thus inheritance for implementation
promotes reuse of previously developed code. Several languages such as C++ and CommonObjects
support for excluding methods of parent class in child class [45, 70].
For data ow anomaly testing, because some of the methods are not inherited in the child class,
the path expressions for those methods that appear later in sequence speci cation change. Because
the path expressions are changed for some of the methods, all the methods in the child class must
be considered for data ow anomaly detection.

5.5 Conclusion
For successfully implementing OO programs, complete and consistent speci cation and an imple-
mentation that is free from bugs compliant with the speci cation is essential. In this chapter, we
have proposed a data ow anomaly detection technique for detecting data related anomalies in a
class. This technique uses the method sequence speci cation technique for specifying the causal
relation that exists between methods of a class. The conventional techniques cannot determine all
the data ow anomalies in reusable classes. Our technique proposed in this chapter, ensures that
there are no data ow anomalies in a class if the methods are invoked in such a way that they are
compliant with the method sequence speci cation. In this paper, we have also discussed about data
ow anomaly detection in child classes when parent classes are data ow anomaly free.

56
Chapter 6

Test Case Generation from


Speci cation
In this thesis, we have discussed extensively on the importance of V&V. V&V is time consuming,
error prone and if V&V is not carried out properly, the nal programs can be buggy and thus can have
signi cant impact on the users. V&V of an implementation is to ensure that the implementation is
consistent and complete with respect to the speci cation. Since the implementation of an application
from design is a manual process, there is bound to be many inconsistencies and incompletenesses in
the implementation. In chapter 5 we have discussed about detecting data ow anomalies from an
implementation. Even though data ow anomalies are serious faults in an implementation, a program
usually consists of many more faults and extensive testing of the implementation is necessary for
identifying and removing all the faults from the program.
Even though the importance of testing is well-known, not many techniques are currently available
for testing OO programs. Testing techniques facilitate generation of test cases from the design or
other speci cation for testing an implementation. E ectiveness of these testing techniques depend
on the quality of test cases that can be generated. Test cases are e ective when they can identify
several faults.
The testing activity can be divided into four stages. They are,
1. Identi cation of the testing criteria.
2. Generation of test cases based on the testing criteria.
3. Execution of the test cases against the target implementation, and
4. Evaluation of the test results.
Test case generation is the second step in testing. Test case generation is driven based on
the testing criteria decided as a rst step of testing. In chapter 1, we have discussed how test
case generation techniques vary depending on the testing criteria. Once the testing criteria is well
de ned, test cases can be generated that can rigorously test a target system against the criteria. In
this chapter, for test case generation we assume the testing criteria of correctness.

57
6.1 Introduction to Test Case Generation
Among all the stages of testing, test case generation is the time consuming and not so prone to
automation. The primary goal in test case generation is to device test cases that can identify faults
in an implementation. As discussed previously, number of admissible test cases for a given design
of a program is extremely huge. Further, since test case generation is an intelligent human activity,
it is expensive. So, the goal of test case generation is to generate less number of test cases that are
e ective in identifying most of the faults in a program.
Test cases are usually generated in three steps.
1. Identi cation of the design or program components for test case generation. These components
can be anything from a single statement to the entire system. In OO paradigm, some example
components are methods, methods in a class, and message sequences through class instances.
2. Speci cation of test inputs and the state of related components that exercise the components
selected in the previous step.
3. Speci cation of expected output of the selected component and the expected state of related
components.
Compared to procedural paradigm, in OO there are several additional types of components.
These components interact with other components in more dynamic way compared to the ones in
procedural paradigm. In procedural designs, the fundamental components were functions or proce-
dures that performed a well de ned task. In OO paradigm, several new types of components are
introduced such as class and methods in a class. The interaction between these components are
more complicated than a procedure or function call due to the introduction of dynamic binding,
polymorphism, and separation of method and message concepts. For successful testing of OO pro-
gram, the interaction between the components must be well studied and from these interactions test
cases must be generated.
6.1.1 Identi cation of Components and Interactions
The fundamental components of an OO design are classes. These classes are designed in such a
way that they are reusable across di erent applications. Once a library of such reusable classes are
available, application development is performed by the composition of these classes and setting up
of domain information in these classes. This concept of reusability has been extensively used in user
interface classes. A user interface is designed using well de ned classes such as menus, windows,
buttons, and scroll-bars. These reusable classes are used in di erent applications under di erent
contexts. These classes might support several methods for di erent behavior, but an application
might use only a subset of these methods. However, to make these classes completely reusable, all
the methods and its interactions must be tested. Therefore, in addition to testing of individual
methods, it is necessary and important that all the method interactions be identi ed and tested.
In this chapter, we describe various techniques for identifying these method interactions for both
within and across classes for generating test cases.

58
6.1.2 Test Input and Expected Output Generation
Once the interacting components are identi ed, the next step in test case generation is to generate
test inputs and the corresponding expected outputs. In chapter 1 we have discussed several issues
related to test input and output generation. A legal test input is the one that is consistent with
the speci cation of the component. Test inputs can be generated automatically, if the speci cation
is well de ned and rigorous. For example, test inputs to test a compiler can be usually generated
from the grammar speci cation of the language for which the compiler is built. In OO paradigm,
test input generation is dicult because the input has to ensure that the interacting components
are exercised while testing.
Generation of expected output for a given input and the target component is expensive. For
speci cation based test cases, input and expected output can be generated from the speci cation.
The test input and expected output includes both the input and output values that a component
uses and returns. In addition, they have to specify the input state and expected output state. The
state of a component is de ned by the current values present in the variables of the component. In
procedural paradigm, the state of the system is usually global as only global variables is shared by
all functions, and all the functions use and modify the state. However, in OO paradigm, the state
is distributed to individual objects as each object maintains its own copy of the instance variables
and therefore, speci cation of input and output states are involving. The speci cation of the state
of objects is more dicult when multiple objects are selected as target components for testing.

6.2 Test Case Generation for Methods


In OO paradigm, methods are the executable components of a class. Methods have access to instance
variables de ned inside an object and they can send out messages to other visible objects. Methods
in a OO program can be compared to functions or procedures of the procedural paradigm. For unit
testing of individual methods, test case generation techniques from the procedural paradigm can
be applied. However, with respect to testing of methods there are new issues due to inheritance,
polymorphism, and dynamic binding. In this section, we discuss these issues in detail.
6.2.1 Application of Procedural Testing Techniques
Extensive research has been done in software testing of procedural programs. Most of the these
testing techniques are applicable to test the individual methods in OO paradigm. In the following,
we brie y identify various test case generation techniques and strategies that are applicable to test
individual methods.
 Coverage Criteria: Test cases can be generated based on various source code coverage criteria.
Examples of the coverage criteria are statement coverage, branch coverage, and condition
coverage.
 Black-box Test Cases: Test cases can be generated from the functional speci cation of a
method. The black-box methods are sub-categorized as random test case generation, partition
based test case generation, and cause-e ect based test case generation. Various partition based
test case generation techniques are input partition, output partition, boundary value analysis,
equivalence partitioning, and so on.

59
 White-box Test Cases: In white-box test case generation, test cases are generated based on the
possible execution paths in a program. Since, there exists large number of dynamic paths in a
program, these paths can be partitioned and test cases can be generated from each partition.
 Data ow Dynamic Test Cases: Test cases can be generated based on the de ne-use pairs of
the data that de ne a sub-path in a method. The number of de ne-use pairs again can be
very large and these pairs can be ltered based on a speci cation.
 State-based Test case generation: A method can change the state of an object based on di erent
input data. If methods functionality can be expressed in a state based design, then state-based
test case generation techniques can be applied to each method for test case generation.
 Inspections and Walkthroughs: Inspections and walkthroughs are manual or computer assisted
comparison of various software development products such as requirements, design documents,
and nal code [23, 48]. Walkthroughs are done by going through the various execution paths
of a program. Inspections are usually done by comparing the target product against a checklist
of possible faults.
6.2.2 Inheritance and Test Case Generation
One of the major bene t claimed in OO paradigm is that it helps in the creation of well-designed,
reusable, and well-tested library of classes. To test the classes in a library one possible approach is
to test every class in the library. This implies testing of every method in the class hierarchy even
though the methods might be unchanged in the parent and child classes. Further, exhaustive testing
of each class does not reuse the test cases developed for the parent class methods. Thus testing of
methods on the inheritance hierarchy can be optimized.
In [62], it has been demonstrated that many of the well tested parent classes have to be retested
in the context of child classes. In [25] it is suggested that methods that are inherited from parent
classes may require minimal testing if their functionality is not modi ed in the child classes. In
[30], authors discuss about incremental testing of classes. In their technique, initially a base class is
tested thoroughly by testing each method. The test case design and test case execution information
is saved along with the base class. Then, when a subclass is de ned, the testing history of the parent
class and the modi cations done to the child class are used to determine the methods in the child
classes that need new test cases. Test cases from parent classes might be used in child classes.

6.3 Test Case Generation


Sequence speci cation speci es the sequence in which an object of a class can invoke methods and
the sequence in which a method in a class sends messages to other class instances. In chapter 2 we
have discussed in detail about sequence speci cation of methods at a single class (MtSS) as well as
across classes (MgSS).
In OO paradigm, it is important to test all the interaction between the methods in addition to
testing of individual methods. Since the number of method sequences can grow exponentially with
the number of methods, it is expensive to test all possible method sequence combinations. Therefore,
we need to use novel test case generation techniques that can reduce the number of test cases, but
at the same time e ective in identifying various faults. In this section, we describe about test case

60
Testing Technique Single Class Multi-Class
Random Testing YES YES
Partition Testing YES YES
Data ow Testing YES YES
Scenario Based Testing NO YES
State Based Testing YES NO
Table 6.1: Summary of Testing Techniques discussed in this chapter

generation techniques that can be applied to generate test cases from the sequence speci cation of
classes. Initially, we discuss about test case generation from single class MtSS. We illustrate each
of the testing techniques with examples. We follow a similar approach for test case generation from
MgSS. In table 6.1 we have listed all the testing techniques that are discussed in this chapter.

6.4 Test Case Generation From Single Class


In this section, we discuss about di erent test case generation techniques from the MtSS of a class.
These techniques can be used for test case generation for both client and server classes. For the
client class test case execution, test stubs are necessary. In the case of server classes, test drivers
are necessary to exercise the test cases of the class.
In this section we discuss di erent test case generation techniques from single class MtSS. We
generate method sequences from the MtSS as a test case. Each of this method sequence is a valid
sequence in the MtSS and depending on the testing technique, di erent sequences are generated. To
use these sequences as test cases, for each of the methods in the sequence, one has to generate test
input and expected output. One can reuse the test inputs and expected outputs that are generated
for unit testing of each of the methods.
The MtSS of a class uses '?' and '+' operators to identify those groups of methods that can be
repeatedly invoked. These operators along with the use of 'j' operator between methods, increases
the number of valid method sequences for a class. To completely test a class, one has to generate all
the valid method sequences and ensure that the instances of the class behave correctly for each of the
method sequence. Because generation and evaluation of each of the method sequence is expensive,
various testing techniques are introduced that reduce the number of sequences one has to test to
identify the faults in a class. In the following we discuss random, partition, and data ow based test
case generation techniques.
6.4.1 Single Class Random Test Cases
Random testing has been used extensively in procedural paradigm, where the test inputs are gener-
ated randomly from input space [57]. Although, traditionally random testing is considered a weak
method, its ease of generating test inputs and power of detecting failures in publicized programs
have been noticed [46]. Random testing is found to be e ective during initial stages of testing, where
the fault space is large enough for adequate random sampling [41].

61
open ( )

setupAccnt ( )

deposit ( )

withdraw ( )
Account
acctSummary ( ) Class
balance ( )

creditLimit ( )

close ( )

Figure 6.1: Account Class Example for generating test cases

A class usually consists of several methods. The MtSS of the class captures the causal order in
which the methods can get executed. Since, the number of valid method sequences corresponding
to the MtSS is huge, we can use random techniques to select a subset of the sequences at random.
Thus, from the MtSS we can generate method sequences randomly as test cases to test the interaction
between the methods. For random test case generation to be e ective, it must be easy to generate
inputs and expected outputs for each of these methods. As we have discussed, each of these methods
are subjected to testing individually. Therefore, one can use the test cases that are generated for
each of these methods to test the interaction between these methods.
Test cases for random testing: Example
In this example, we discuss about generating random test sequences from the Account class ( g-
ure 6.1). The Account class has eight methods and the method names describe the functionality of
each of the methods. The MtSS of the Account class is,
MtSS ) open  setupAccnt  deposit  (depositjwithdrawjbalancej
acctSummaryjcreditLimit)?  withdraw  close (6.4.1)
In the MtSS 6.4.1, the rst deposit() method is the initial deposit to the account. Then any
of the transaction methods can be sent to instance of Account class until the nal withdraw() and
close() methods of the object are invoked. From the MtSS 6.4.1, many valid method sequences can
be generated. Number of sequences that can be generated from the above MtSS is in nitely large
as there is a ? operator in the MtSS indicating that several of the above methods can be repeated
any number of times. Any valid method sequence that satis es the above MtSS is a candidate for
a valid test case. For example, if deposit() and balance() methods are selected randomly from the

62
Method Expected Output Expected State
open(a/c-no = 12345) object opened balance = 0
creditLimit = 0
setupAccnt(creditLimit=2000) setupAccnt successful creditLimit = 2000
deposit(amount = 150.00) deposit successful balance = 150.00
deposit(amount = 2000.00) deposit successful balance = 2150.00
balance() returns 2150.00 balance = 2150.00
withdraw(1500.00) returns 1500.00 balance = 650.00
close(a/c-no = 12345) fails due to -
nonzero balance
Table 6.2: Example of random test case with test inputs and expected outputs.

MtSS 6.4.1, we get the following random test sequence.


TestCase1 ) open  setupAccnt  deposit  deposit  balance 
withdraw  close (6.4.2)
The test sequence 6.4.2 consists of 7 methods in a sequence. Test inputs and expected output for
each of the methods in the test sequence /refrand:test:one form a random test case. An example of
a complete test case consisting of test inputs and expected outputs is given in table 6.2. A sample
of test sequences that are generated randomly are given below:
TestCase2 ) open  setupAccnt  deposit  creditLimit  balance
withdraw  close (6.4.3)
TestCase3 ) open  setupAccnt  deposit  withdraw  creditLimit 
withdraw  close
TestCase4 ) open  setupAccnt  deposit  acctSummary  deposit 
withdraw  close
TestCase5 ) open  setupAccnt  deposit  withdraw  balance 
withdraw  close

Test cases for random testing: Special cases


A: Minimal Test Sequences: While generating random test cases a special case of minimal method
sequences can be generated for random testing. A minimal method sequence is the one that is
consistent with the MtSS and does not contain any other valid method sequence as a subsequence
of it. A minimal sequence in 6.4.4 is generated from the MtSS 6.4.1.
MinimalSeq ) open  setupAccnt  deposit  withdraw  close (6.4.4)
In the minimal sequence all those methods that are optional due to '?' operator are not included
for test sequence generation. If a group of methods is followed by a '+' operator and each of the

63
method in the group is separated by 'j', then one method from the group is selected for minimal test
sequence. Thus, more than one minimal test sequence is possible from the MtSS of a class.
B: All Methods Sequence: When generating test sequences, one can constrain that all the methods of
a class must be included. An all methods random test sequence is the one that is consistent with the
MtSS and contains all the methods of a class if possible. There can be more than one 'all methods
sequence' possible from the MtSS of a class. An all method random test sequence generated from
the MtSS 6.4.1 is shown below:
AllMethods ) open  setupAccnt  deposit  creditLimit  deposit 
balance  accntSummary  withdraw  close (6.4.5)
Test cases for random testing: Discussion
In random test case generation, no domain information is used in generating test cases. Therefore,
random test case generation is considered a weak method. The random test sequences in general
are inexpensive as not much e ort is required for the generation. They are useful during the initial
stages of testing as the fault-prone region is large.
Even though the generation of random test sequences is easy and inexpensive, generation of test
inputs and expected outputs for each of the method in the test sequence is involving. For each of
the methods, one can further use random testing technique to generate test inputs and expected
outputs. Other alternative is to use the same test cases that were generated as unit test cases for
individual methods.
Boundary condition testing is always stressed in testing as faults do occur frequently in end
conditions. In this regard, the minimal test sequence and all method test sequences are useful to
ensure that the class is functionally correct under these conditions. In the MtSS 6.4.1, number of
all methods test sequences are ve as there are ve methods inside the '?' operator and there can
be ve permutations of the methods resulting in ve test sequences.
In random test case generation the domain information is not used and therefore they may not
be e ective. By combining the domain information and the sequence speci cation, one can generate
more powerful test sequences. In the next section, we discuss about partitioning the methods or
state and generating test sequences based on the partitions.
6.4.2 Single Class Partition Test Cases
As opposed to random testing, partition testing reduces the number of test cases required by parti-
tioning the input or output space into categories and sampling test cases from each category. The
success of partition testing depends on the presence of the problem speci cation and a good partition
criteria. Partition testing is found to be e ective when the faults in a program are not distributed
uniformly.
As the number of methods in a class and its interaction with other methods of the class increases,
the number of method sequences that can be generated from the MtSS of the class also increases.
Testing of all the sequences is expensive and some times impossible. Therefore, it is often necessary
to partition the methods into several partitions and select methods from each partition for generating
test cases. It is also possible to partition the state into several categories and generate test sequences
to test each of the state partition. Thus partition testing tries to reduce the number of test cases
required by partitioning the test space into categories and sampling test cases from each category.

64
The success of partition testing depends on the partition criteria. We discuss several partitioning
criteria and discuss about test sequence generation from each partition. Thus, partition testing uses
domain information for partitioning the methods or state information into groups.
Test cases for partition testing: Example
We will consider the same example that was used to generate method sequences for random testing.
The Account class drawn in gure 6.1 supports 8 methods among which ve of those are of transaction
type. We can partition the transaction type methods into partitions based on a partition criteria.
We can rewrite the MtSS 6.4.1 as,
SeqSpec ) open  setupAccnt  deposit  Transactions 
withdraw  close (6.4.6)
Transactions ! (depositjwithdrawjbalancejacctSummaryj
creditLimit)? (6.4.7)
In the MtSS 6.4.7, because of the '?' operator, all the transaction methods are optional. Further,
because '?' is a repeat operator, the methods can be used in any order for any number of times.
Therefore, number of method sequences that can be generated is in nite.
The transaction methods in the MtSS 6.4.7 can be split into partitions using a partition criteria.
In the following we discuss di erent partitioning criteria and test case generation from each of the
partition.
A: State Based Partitioning: In state based partitioning criteria, methods can be partitioned
based on those that change the state. In the MtSS 6.4.7, the methods deposit() and withdraw() are
the ones that modify the state, while the methods balance(), accntSummary(), and creditLimit() are
the ones that do not change the state. Thus, in MtSS 6.4.7, the transaction methods can be grouped
into two partitions as,
Transaction ) (StateMethodsjNonStateMethods)?
StateMethods ! (depositjwithdraw) (6.4.8)
NonStateMethods ! (balancejacctSummaryjcreditLimit) (6.4.9)
Thus for generating method sequences for partition testing, we use methods from each partition.
For example, a test method sequence generated from state a ecting methods is,
PartitionTestCase1 ) open  setupAccnt  deposit  depositdeposit 
withdraw  close (6.4.10)
In the test method sequence 6.4.10, the deposit() method is used twice. Similarly a test method
sequence generated from non-state a ecting methods is,
PartitionTestCase2 ) open  setupAccnt  deposit  creditLimit
acctSummary  withdraw  close (6.4.11)
In the test cases 6.4.10 and 6.4.11 the underlined methods are the ones that are generated from
di erent partition classes.

65
Category Methods
initialize open( ), setupAccnt( )
query balance( ), creditLimit( ), accntType( )
operations deposit( ), withdraw( ), accntSummary( )
release close( )
Table 6.3: Category based partitioning of the Account class methods

Each of the partitioned categories can be further partitioned. For example, if an account should
not allow more than three withdraws per day, then from 'state a ecting partition', a test sequence
can be generated.
B: Attribute Based Partitioning: In attribute based partitioning scheme, the methods are par-
titioned based on the attributes (instance variables) they use. This partitioning criteria is similar
to the state-based criteria, but this criteria further divides the methods into various categories de-
pending on the variables they use and modify. In the Account class, the important attributes are
balance and cred limit. We can divide the transaction methods in 6.4.7 into three categories based
on the methods that use, modify, and do not use or modify the attribute cred limit. The meth-
ods deposit() and withdraw() modify cred limit, the methods deposit(), withdraw(), creditLimit() use
cred limit, while acctSummary() and balance() neither use or modify cred limit. Thus, the MtSS 6.4.7
containing transaction methods can be classi ed as follows:
Transaction ) (UsejModifyjNoAccess)? (6.4.12)
Use ! (depositjwithdrawjcreditLimit) (6.4.13)
Modify ! (depositjwithdraw) (6.4.14)
NoAccess ! (balancejacctSummary) (6.4.15)
From the di erent partitions of the methods in 6.4.13, 6.4.14, and 6.4.15, one can generate
test method sequences for partition test cases. For example, a test sequence generated from the
partition 6.4.13 is,
PartitionTestCase3 ) open  setupAccnt  deposit  withdraw
creditLimit  withdraw  close (6.4.16)
C. Category Based Partitioning: The methods of a class can also be partitioned to several
categories depending on the operations they perform. In Smalltalk [28], class and instance methods
are divided into several categories for the purpose of easy understanding and grouping. One can
use the same partition to generate test method sequences. In category based partition scheme, one
has to write the MtSS at the category level rather than individual method level. For example, in
table 6.3 the methods of the Account class are categorized into four categories.
The MtSS of the Account class can be written using the above categories. An example MtSS is
shown below.
SeqSpec ) Init  deposit  (QueriesjOperations)?  withdraw 

66
Release (6.4.17)
Init ! open  setupAccnt (6.4.18)
Operations ! (depositjwithdrawjaccntSummary) (6.4.19)
Queries ! (balancejcreditLimitjaccntType) (6.4.20)
Release ! close (6.4.21)
In the above, the MtSS of Account is divided into four categories. Among those, only the
Operations (partition 6.4.19) and Queries (partition 6.4.20) categories participate in variety of test
method sequence generation as the methods in the category Init (partition 6.4.18) and Release
(partition 6.4.21) must be present in each of the method sequence. Thus, an example method
sequence generated from Queries partition is given in equation 6.4.22.
CategoryTestCase ) open  setupAccnt  deposit  creditLimit
accntType  withdraw  close (6.4.22)
In the test method sequence 6.4.22, the underlined methods are the ones that are selected from
the category Queries.
Test cases for partition testing: Special cases
In the following we discuss special cases of partition test method sequence generation.
A: All Methods Partition Sequence: When generating test method sequences from partitions,
one can constrain that all the methods from a partition must be included. Thus, an all method
partition sequence is one that is consistent with the MtSS and contains all the methods from a
selected partition if possible. As an example, an 'all method partition sequence' generated from the
Operations category of category partition scheme would include all the methods from the Operations
category (refer table 6.3). An example for all methods partition sequence from the Operations
category is given below:
AllPartMethods ) open  setupAccnt  deposit  deposit  withdraw 
acctSummary  withdraw  close (6.4.23)
B: Cross Partition Method Sequence: In the partition method sequence generation discussed
so far, methods were grouped into several partitions and from each partition methods were selected
for generating a test method sequence. An other useful alternative is to select methods from all the
partitions to form a test method sequence. By doing so, a representative method from each of the
partitions is selected and thus the test cases sample all the partitions. For example, in attribute
based partitioning scheme, methods are partitioned into three categories as given in MtSS 6.4.12.
A cross partition method sequence generated from the three partitions, Modify, Use, and NoAccess
of the MtSS 6.4.12 is given below:
CrossPartMethods ) open  setupAccnt  deposit  creditLimitUse 
withdrawModify  balanceNoAccess  withdraw 
close (6.4.24)
In the test method sequence above, the methods that are selected from di erent partition groups
are shown as a sux to the methods. i.e. the method creditLimit() is selected from the partition use,

67
the method withdraw() is selected from the partition modify, and the method balance() is selected
from the partition NoAccess.
Test cases for partition testing: Discussion
In partition test case generation, usually the input space is partitioned into several categories and
test cases are selected from each category. In this chapter, the input space for partitioning is the
methods supported by a class and state space. We have discussed three di erent partitioning criteria
for classifying the methods into partitions.
Partition testing is more useful in situations where a class supports a large number of methods.
For example, in NeXTSTEP or OpenSTEP OO programming environment, the user interface classes
such as Text, TextCell, and Button on the average have 25 methods [59]. With more than 500
user classes in total, generating test cases for each of the class can be dicult. Thus, partitioning
the method space into several partitions is helpful.
The e ectiveness of partition based test cases depend on the e ectiveness of the partitioning
criteria. Partition based test cases are e ective when a program has non-uniform fault-prone region.
Partition based test cases perform well when the partition criteria categorizes the partitions into
those that are dense in faults. Thus, a good partitioning criteria categorizing methods into partitions
that can identify most of the faults is useful.
Even though a partition scheme partitions the methods into several categories, the number of
test cases that must be generated from each partition can still be huge if the MtSS containing the
methods of the partition use '+' or '?' operators. In the next section we discuss about data ow
based test method sequence generation technique which uses domain information in generating test
cases.
6.4.3 Single Class Data Flow Test Cases
The data ow testing uses the data ows between di erent components of a software for generating
test cases. Data ow testing helps to identify the path incompleteness, redundancies, and ambiguities
in an implementation. Data ow testing strategies are structural strategies that can be used to
construct test paths. Data ow testing strategies use operations on data objects as a criteria for
selecting subpaths for testing. Di erent strategies can be derived based on de ne, use, kill operations
on data objects.
In OO programs, data ow testing can be carried out within a method as well as across methods.
In this chapter, we concentrate on the data ow testing across methods. Data ow testing within
a method is similar to the one used in procedural techniques. A class supports a set of instance
methods that de ne, use, and modify the instance variables of the class. The instance variables
are global to all the methods de ned in the class. Some methods usually initialize and update the
instance variables while other methods use those data in computation. Thus, there is a data ow
across the methods and one can generate di erent test cases depending on this data ow.
In data ow test case generation, the rst step is to identify a de ne and use pair of a data value.
In OO, that corresponds to nding out the methods that de ne and use an instance variable. Then
a test method sequence can be generated such that it contains the method that de nes the variable
as well as the one that uses the variable. There can be more than one method that de nes and uses
the same instance variable. Similarly, within a method, an instance variable can be de ned or used
more than once. For de ning a test method sequence, a set of methods are selected such a way

68
that they satisfy the MtSS of the class and a method in the sequence de nes the selected instance
variable and another method in the sequence uses the selected instance variable. Thus for data ow
based test case generation, we use the de ne and use information of variables and the MtSS of the
class. To illustrate various data ow based test sequence generation strategies, we introduce the
following code fragment.
class Account{
public:
...
int setupAccnt(int crdlimit, char * address, ...);
float creditLimit ( );
...
protected:
float balance;
float cred_limit;
...
}
int Account::setupAccnt(int crdlimit, char * Address ...)
{
...
cred_limit = crdlimit;
...
}
float Account::creditLimit ( )
{
...
if(balance > 2000)
return balance;
else
return cred_limit;
...
}

Test cases for data ow testing: Example


We use the Account class to illustrate the data ow test case generation. From the gure 6.1 of the
Account class, let us consider two methods setupAccnt() and creditLimit() whose source code abstract
is given above. The method setupAccnt() sets up the account information, initializes the cred limit
instance variable and address. Thus, the method setupAccnt is de ning the value of an instance
variable cred limit. The method creditLimit() uses the instance variables cred limit and balance to
compute the actual credit limit. Thus, the method creditLimit() uses the instance variable that was
de ned by the method setupAccnt(). This de ne-use pair of the instance variable cred limit can be
used for test case generation from the sequence speci cation 6.4.1.
From the sequence speci cation 6.4.1, various method sequences can be generated. All the
method sequences that use the methods setupAccnt() and creditLimit() without any intermediate
methods that access the instance variable cred limit are valid data ow test sequences. In the

69
following, we give a sample of these test cases.
TestCase1 ) opensetupAccnt  deposit  accntSummary 
creditLimit  withdraw  close
TestCase2 ) opensetupAccnt  deposit  withdraw 
creditLimit  withdraw  close
In the above test cases, the methods that are underlined are the ones that are de ning and using
the selected instance variable.
Special cases of data ow test cases
A class usually contains several instance variables. Instance methods of the class access these
instance variables and there can be more than one instance method that de ne and use the data.
Thus, there can exist many de ne-use pairs and one can identify many special cases of data ow test
cases depending on the number of such pairs that are included for test cases. In conventional data
ow testing, there exists several testing strategies. We use the similar strategies in OO paradigm.
In the following we discuss many of these special cases.
In all-du-sequence testing strategy it requires that every minimal sequence of methods from the
every de nition of every variable to every use of that variable be considered for data ow testing.
This strategy for generating test cases is the strongest criterion as it generates test cases that can
be generated from any other data ow strategies. In all-use-sequence case it requires to generate at
least one de nition free minimal sequence of methods from every de nition of every variable to every
use of the variable. Similarly the above strategies can be extended with all-de nitions-sequence, all-
predicate-use-sequences, and all-computational-use-sequences.

6.5 Inter Class Test Case Generation


In the last section we have discussed about test case generation from a single class. We used the
MtSS of the classes for generating test cases to test classes. In this section, we introduce new test
case generation techniques for testing the method interactions across classes. We use the MgSS of
all the methods to test the method interactions. We then introduce test case generation techniques
that use MtSS and MgSS together. The test cases generated from multiple classes can be considered
as integration test cases as they test the integration of methods between the classes.
The MtSS of a class captures the causal order in which the methods of an instance of a class can
be invoked. In the last section, we used the causal order speci cation at a class for generating test
cases. The MgSS describes the causal order among the methods supported by di erent classes. The
MgSS is speci ed for each of the method that sends out messages to class instances. In this section,
we describe about test case generation techniques that use MgSS.
To illustrate various test case generation techniques for multiple classes we use the ATM design
as an example. The design of the ATM and all the supporting classes are shown in the gure 6.2 and
gure 6.3. In gure 6.2, two classes ATM UI and ATM are shown. The class ATM UI is the class that
represents the actual ATM machine that includes the user interface, cash dispensing unit, keyboard
and so on. The ATM class is the one that interacts with the Bank class and supports all the ATM
operations.

70
cardInserted
password
deposit
withdraw
accntStatus
ATM operations
terminate

ATM UI ATM
verifyStatus
depositStatus Bank Class
dispenseCash
print accnt stat
readCardInfo
getCashAmnt

Figure 6.2: Class Interaction Diagram for ATM Design: Part1

71
verifyAcct creditLimit

verifyPIN accntType

verifyPolicy balance
BANK ACCOUNT
ATM

withdrawReq withdraw

depositReq deposit

acctInfo close

validPIN
authoriseCard
initialDeposit

deauthorise
openAcct

closeAcct
validAcct

ACCOUNTINFO

CASHIER

Figure 6.3: Class Interaction Diagram for ATM Design: Part2

In gure 6.3, four classes of the ATM design Bank, Cashier, Account, and Account Info are shown.
The Bank class interacts with ATM class. Methods in Bank class sends out messages to instances of
Account class and Account Info class. Similarly the Cashier class interacts with Bank class.
We rst discuss generation of test sequences from MgSS. We then discuss about test case gener-
ation using both MtSS and MgSS.
6.5.1 Test Cases from Method Interactions
In OO paradigm, objects are the run-time entities and methods are the basic units that perform
the computation. Methods usually use the services of other objects by sending messages to them.
So, testing in OO is to generate test cases that checks the correctness of this method-message
interactions.

72
The primary goal is to generate test cases that test each method interactions with instances of
other classes. We can divide the method interactions into those with neighboring classes and with
all the classes. As we have discussed before, MgSS of a method captures the interaction of a method
with its neighboring classes. Using, MgSS we rst generate a set of test cases to test the method
interactions between neighboring classes. We then extend the test case generation techniques to
include all the classes.
Method interactions between neighboring classes
As we have discussed before, the MgSS of a method identi es all the messages it sends out to other
objects. It also identi es the causal order in which the messages are sent out. The MgSS speci cation
uses the regular expression formalism. In addition to the operators ' ', 'j', '+', and '*' we use a new
operator '?' that indicates that a message pre xed to the operator '?' is optional.
For a given MgSS of a method, the goal is to generate test sequences from the MgSS. The MgSS
of a method can represent several possible message sequences. Further, each class can have several
methods and each of those methods might send out messages to other objects. Therefore, it is
necessary to identify and develop test cases for each of the methods that send out messages to other
classes.
MgSS of a method represents all possible message sequences in which a method can send out
messages. Let a method m1 of class C 1 send out messages m2, m3, m4, m5, and m6 to di erent
instances of classes. Let the MgSS of the method m1 be,
m1C 1 ) m2O2  (m3O3jm4O4jm5O5)?  m6O6 (6.5.25)
From the the MgSS 6.5.25, one can generate several test sequences. Since the above MgSS can
generate in nite number of test sequences, one can use many of the testing techniques described
in the previous section to generate test sequences. For example, one can use random techniques to
generate test sequences from the MgSS. Similarly, one can partition the messages that are sent out
from the method and then generate test sequences.
Test sequences from MgSS of a method: Example
For example, let us consider the ATM design in the gure 6.2 and the gure 6.3. In gure 6.3 several
methods of the class ATM sends out messages to the instances of the class Bank and ATM UI. The
method withdraw() of ATM class sends out messages to Bank and ATM UI class. The MgSS of the
method withdraw() is given below:
withdrawATM ) getCashAmntATM UI  verifyPolicyBank 
withdrawReqBank  dispenseCashATM UI (6.5.26)
In the MgSS 6.5.26, the method withdraw() sends out messages to the classes Bank and ATM UI.
Since, the MgSS corresponds to one sequence that is possible, this forms a test sequence. The above
test case involves the support of other classes during test case evaluation. In this technique, it is
necessary to generate test cases for all the methods that interact with neighboring classes.

73
Method interactions across all related classes
In the last section, MgSS of a method is used for generating test cases. With response to each of the
messages sent out, the receiving object executes a method. In this section, we use the MgSS of the
methods in the neighboring classes and combine with the MgSS of the original method that initiates
messages to generate test sequences. For example, in the MgSS 6.5.26, the withdraw() method sends
out messages such as verifyPolicy() to Bank class. We use the MgSS of the method verifyPolicy() of
the Bank class to enhance the test case derived from the MgSS 6.5.26. Test cases generated might
include several classes through a chain of message-method pairs.
Test sequences from MgSS of a set of methods: Example
For example, the test case derived from equation 6.5.26 is expanded below that includes the entire
chain of methods. The key here is to identify the methods and the temporal order in which these
methods might get executed. The MgSS of the methods verifyPolicy() and withdrawReq() of the class
Bank is given below.
verifyPolicyBank ) balanceAccount  creditLimitAccount (6.5.27)
withdrawReqBank ) withdrawAccount (6.5.28)
The MgSS in equation 6.5.27 and equation 6.5.28 contain only '' operator. Therefore, from these
MgSS only one message sequence can be generated. These message sequences can be substituted
to the test sequence derived from the MgSS 6.5.26 to get a new message sequence that span the
instances of Account class. The test case 6.5.29 contains the all the methods that are expanded. The
messages inside the square brackets ('[') are the messages that the method present before the bracket
sends out. The sux of each of the message indicates the class to which the message belongs.
withdrawATM ) getCashAmntATM UI  verifyPolicyBank  [balanceAccount 
creditLimitAccount]  withdrawReqBank  [withdrawAccount] 
dispenseCashATM UI (6.5.29)
The above test sequence can be used as integration test as they span multiple classes. Further, test
sequences that are generated to test neighboring classes can be enhanced further with the expansion
of each of the messages. In fact, a test sequence can be expanded all together until each of the
messages ends up at an object that does not send out any more messages.
6.5.2 Multiple Class Data Flow Test Cases
In section 6.4.3 we have discussed about data ow test case generation from a single class using
de ne-use pairs on an instance variable. In this section we discuss about generating test cases using
data ow information across objects. In this technique, the data we use is not instance variables,
but the domain data. Domain data is a data that represents some information in the domain. This
data is transferred from one object to other object as an argument to messages, or as a part of an
object which is passed as an argument to other object. For example, the domain data in ATM is
deposit money, withdraw amount, balance left in the account, and account information.
Generation of a data ow test cases spanning multiple classes is done in three steps:

74
1. Identi cation of the domain data that is read, de ned, used, and computed across class in-
stances.
2. Identi cation of the criteria of data access such as de ne-use, read-use, or create-use of the
domain data.
3. Identi cation of a sequence of methods belonging to di erent classes that links up the method
that de nes the domain data and a method that uses the domain data.
For the third step above, we need MgSS of several methods to link up the methods.
Test cases for data ow testing: Example
In gure 6.2 and gure 6.3, a set of interacting classes are shown. If we consider the deposit amount
as the domain data, the data is input at the ATM-UI from the account holder and later a ects the
balance amount in an instance of Account class. So, the method deposit() in ATM class reads the
data and various methods such as accntSummary() and balance() of Account class uses them. Thus, a
method sequence linking these methods in di erent class instances form a data ow test case. From
the perspective of ATM UI, the method deposit() de nes the data and the method accntStatus() uses
the data. Test sequences linking these two methods are:
DataDefine ) depositATM  getCashAmntATM UI  depositReqBank 
depositAccount (6.5.30)
DataUse ) acctStatusATM  acctInfoReqBank 
balanceAccount (6.5.31)
In equation 6.5.30 a method sequence de nes the data and in equation 6.5.31 a method sequence
uses the data that was de ned by the rst sequence. These two method sequences form a data ow
test case.
In the previous two sections, we have discussed about test sequence generation that spans single
class as well as several classes. In the coming sections, we discuss about generating test sequences
that can test the system as a whole. The system level test sequences involve multiple classes. The
test cases generated at a class level are used for generating test sequences for testing at the system
level.
6.5.3 Multiple Class Random Test Cases
In the last section, we have discussed about random test sequence generation from a single class.
In this section, we discuss about random test sequence generation that spans multiple classes. We
can use random test sequence generation to design test cases for integration testing or system level
testing. The technique we describe in this section can be used for generating both kind of test cases.
The multiple class random test cases are generated with respect to a class. A class that has
methods sending out messages to objects is identi ed. A test case is generated randomly to test the
class under consideration. This test case is expanded to include chains of message-method pairs so
that the test case spans several class instances. The four steps in random test sequence generation
that tests the interaction between multiple classes is given below:

75
1. For each client class that has methods sending out messages to other classes, generate a random
test sequence from its MtSS (similar to the one explained in section 6.4.1) or use a sequence
that has been already generated for that class.
2. For each of the message in the test sequence, determine the corresponding method in the target
object.
3. Determine the MgSS of the method and generate a test sequence from the MgSS using the
techniques described in section 6.5.1.
4. Substitute the newly generated sequence in the original generated test sequence to form a
complete random test sequence.
The random test sequences can be generated incrementally. Initially test sequences can be
generated for server classes. Then, for the client classes test sequences from the server class can be
used to form test cases that span several classes. In the following we describe random test sequence
generation with an example.
Test cases for random testing: Example
Let us consider classes from which we can generate test cases that can be used for integration testing
rather than system level testing. For integration test case, we need to use the intermediate classes
that receives messages and sends out message to other classes. For example, in gure 6.3, the Bank
class sends out messages to Account class. The sequence speci cation of the Bank class with respect
to ATM interface is,
SeqSpecBank ) verifyAcct  verifyPin  ((verifyPolicy 
withdrawReq)jdepositReqjacctInfoReq)? (6.5.32)
A random test sequence generated from the sequence speci cation given in equation 6.5.32 is,
TestCase ) verifyAcct  verifyPin  depositReq (6.5.33)
As explained above, we can determine the MgSS of the methods corresponding to the methods
verifyAcct(), verifyPin(), and depositReq(). We can generate a test case from each of the MgSS and
substitute the same in 6.5.33. We can expand the test sequence 6.5.33 using the sequences generated
from MgSS to make a complete test sequence that can test the integration of the class Bank and
Account. The test case is,
RandCase ) verifyAcctBank [validAccAccInfo]  verifyPinBank
[validPinAccInfo]  depositReq  [depositAccount ] (6.5.34)
The above test case sends out messages to instances of AccInfo and Account class. AccInfo class
instances store all the information about accounts and the password.

76
6.5.4 Multiple Class Partition Test Cases
This technique is similar to the previous technique of random test case generation except in the
way initial test sequence is generated. Initially a class that must be subjected to multiple class
partition testing is selected for test case generation. Using the technique of generating partition test
sequences from the MtSS (see section 6.4.2), a test sequence is generated. The test sequence then
can be expanded to include many chains of method-message pairs until messages end at objects that
do not send out messages.
The partition test sequences generated for the single class testing can be reused here. Alterna-
tively, we can use a new partition criteria and generate test sequences from each of the partition.
The methods can be easily partitioned based on multiple interfaces. For example, the class Bank,
has two types of messages incident on it, one from ATM class and other from Cashier class. So,
the methods supported at Bank class can be partitioned into two categories. Further, each of the
category can be partitioned based on those that modify the state versus those that does not modify
the state. In the following, we use the state based partition criteria to generate a partition test
sequence.
Test cases for partition testing: Example
Let us consider a sequence speci cation of the methods supported by the Bank class in equa-
tion 6.5.32. We can partition the transaction methods into state a ecting and non state a ecting.
The state a ecting methods are depositReq() and withdrawReq() while the non state a ecting method
is acctInfoReq(). A test case generated from the non-state a ecting partition is,
TestCase ) verifyAcct  verifyPin  acctInfoReq (6.5.35)
From the above test case, we can generate a complete partition test case by expanding each of
the method all the way into its constituent messages. i.e.
PartTestCase ) verifyAcctBank [validAccAccInfo]  verifyPinBank
[validPinAccInfo]  acctInfoReq  [balanceAccount 
creditLimitAccount] (6.5.36)
6.5.5 Scenario Based Test Sequence Generation
An OO software system usually consists of several subsystems. Several classes are used for imple-
menting each of the subsystem. The subsystems interact with one another and their interaction
is well de ned. One can write several scenarios in which these subsystems can be used. In the
ATM example, user interface for the account holders is one subsystem that interacts with Bank and
Account classes. Similarly, for bank operators there can be another subsystem that interacts with
Bank and Account classes for entering and administration of the account information. Each of the
above subsystems must be used in a well de ned manner and scenario based testing helps in ensur-
ing that at the highest level these subsystems function properly. In addition, scenario based test
sequences are also useful to test the end-user classes. These test sequences can also be used as a
system level test cases. The scenarios between the system and the user is captured for testing the
major interactions and information exchanges.
Scenarios must be constructed for normal situations rst and then for exception situations. In
the following we describe scenario test cases for normal situation only.

77
Test cases for scenario testing: Example
Let us consider the ATM-UI class drawn in gure 6.2 for generating the scenario test sequences. The
MtSS for the ATM-UI class is,
SeqSpec ) insertCard  enterPin  selectAccount 
((deposit  enterAmt)j(withdraw  enterAmt)j
acctInfo)?  terminate (6.5.37)
A scenario test case is any scenario that the account holder would perform to ATM-UI class.
For example, money withdrawing is a good scenario. Similarly depositing money or getting account
information such as balance, credit limit and so on. For each of the scenario, it can be expressed as
a sequence of messages to ATM-UI class and that forms a scenario test case. This test cases can be
used during system level testing. For example, for account information scenario, the test sequence
is,
TestCase1 ) insertCard  enterPin  selectAccount 
acctInfo  terminate (6.5.38)
Similarly, for withdraw scenario, the test sequence can be,
TestCase2 ) insertCard  enterPin  selectAccount 
withdraw  enterAmt  terminate (6.5.39)
Thus, for each kind of functionality supported at interface classes, one can generate several scenario
based test sequences. The scenario based test sequences can be used during integration or system
level testing.

6.6 Test Case Generation from State Transition Diagram


State Transition Diagram (STD) captures the dynamic behavior of a class. STD of an instance of
a class captures the states of the object, the methods it receives and the messages it sends out.
In each of the state, the messages that the object can receive and the messages it can send are
represented. A valid method sequence that can be derived from the MtSS of the class must have a
corresponding path through the STD of the class instance. STDs are useful to model control rich
classes. In this section, we describe simple techniques that can be used to generate test sequences
from state transition diagram. We explain each of the technique with an example. In chapter 2,
we have shown the equivalence between the MtSS and the state transition diagram of a class and
techniques for deriving one from the other. However, during design phases, constructing STD may
be more easier than constructing the sequence speci cation. In those cases, we can use the STD
itself for generating test cases.
Figure 6.4 shows a state transition diagram of an Account class instance with each of the edge
corresponding to a method of the Account class. In the state Working Accnt the object can invoke
deposit(), withdraw(), balance(), credit(), and acctInfo() methods for any number of times until it
invokes a nal withdraw() method to change its state to non operational account. A close() method
at the end makes the account dead. In the following we describe two simple test sequence generation
from the state transition diagram.

78
Empty
open
Accnt

setupAccnt

Setup
deposit
Accnt

deposit
withdraw

Working Non
withdraw
Accnt working

balance
credit close
accntInfo

Dead
Accnt

Figure 6.4: State Transition Diagram for the Account Class

79
6.6.1 All State Coverage Method Sequences
The STD of a class contains many states and at each state it contains many method invocations.
The all state coverage method sequence is one that contains method invocations at every state of
the class and is compliant with the MtSS of the class. There can be many such sequences possible.
All state method sequences help in ensuring that the instances can go through the start state to
end state through all the intermediate states. If there are multiple paths in the STD then, all state
coverage criteria selects a path through all the states. In the following, we illustrate the all state
coverage criteria with an example.
All state coverage method sequence: Example
In gure 6.4, the STD of Account class is shown. An all state coverage method sequence can be
derived from the STD by following from start state to end state of the STD. A set of method
sequences that forces the object of Account to go through all the states are given below:
TestCase1 ) open  setupAccnt  deposit 
withdraw  close (6.6.40)
TestCase2 ) open  setupAccnt  deposit 
deposit  credit  withdraw  close (6.6.41)
TestCase3 ) open  setupAccnt  deposit 
withdraw  accntInfo  withdraw  close (6.6.42)
In the above examples, the test sequence 6.6.41 and 6.6.42 contains more than one method at each
state. In test sequence 6.6.40, the method open() to Account class creates an object with empty
account state. The method setupAccnt() to the account object makes it an object with all the
account information. The deposit() method makes the object operational. The nal withdraw()
method that withdraws all the money from the account makes the object non working. Finally
close() method makes the account object a dead account.
6.6.2 All Method Coverage Sequences
An STD of a class contains several states. At each state, many methods can be invoked. A method
invocation at a state of an object might result in the same state. The criteria of all method coverage
sequence is one that has all the methods of the class in the sequence and is compliant with the MtSS
of the class. The all method coverage sequence may generate a test sequence that may not involve
all the states of the object. It is possible that a test sequence might not include all the methods
of a class. In that case, one must generate more than one test sequence so that all the methods
are included. In the following we illustrate the generation of all method coverage sequence with an
example.
All method coverage sequence: Example
From the gure 6.4, we can follow from start state to end state and include all the methods in the
sequence they are invoked. At a state if there are more than one method that can be invoked, then
the sequence of the methods can be selected randomly. For example, in state working account there

80
are ve methods and each of the methods can be invoked in any order. A test sequence that satis es
the all method coverage criteria is given below:
TestCase1 ) open  setupAccnt  deposit 
balance  withdraw  credit  accntInfo 
withdraw  close (6.6.43)
The test sequence 6.6.43 contains all the methods of the class. There exists several possible test
sequences that satisfy the all method coverage criteria.

6.7 Test Case Generation for Robustness


In this chapter, so far we have described several test case generation techniques and all these testing
techniques generate test cases for checking the correctness of the target classes. It is also important
to generate test cases to test the robustness of the classes. One way to test the robustness is to
generate negative test cases or dirty test cases [6]. A negative test case is a test case with invalid
data so that the target code can identify and raise exceptions. In this section, we discuss techniques
for generating negative test cases from MtSS and MgSS.
6.7.1 Negative Test Sequences from MtSS
The MtSS of a class de nes a causal order in which methods of the class can be invoked. The MtSS
of a class identi es all possible valid sequences in which the methods can be invoked. A sequence
that is not compliant with the MtSS of a class is thus a negative test case. As discussed before,
we use regular expression formalism to represent the MtSS. The operators used are '' to represent
an immediate sequence, 'j' to represent exclusive-or, '?' corresponds to a zero or more number of
times, and '+' corresponds to one or more number of times. Even though, several techniques exist
for generating various negative test sequences, in the following, we discuss three techniques for
generating negative test cases from MtSS.
Method dropping
In this technique, a method that is a must in any sequence is not selected to generate an illegal
method sequence. For a given MtSS, if there are n methods that appear in every sequence, then
one can generate n negative test sequences by dropping each method at a time. Depending on the
methods dropped, the class can take di erent corrective actions.
Method dropping: Example
Let us consider the MtSS of Account class from which we generate negative test cases.
MtSS ) open  setupAccnt  deposit  (depositjwithdrawjbalancej
acctSummaryjcreditLimit)?  withdraw  close (6.7.44)
The MtSS 6.7.44 represents the causal relation among several methods of the Account class. In the
MtSS, the methods open(), setupAccnt(), deposit() (the rst deposit), withdraw() (the last withdraw),

81
and close() must appear in every test sequence generated. By dropping one or more of these methods,
one can generate a negative test sequence. i.e. by dropping the setupAccnt() method we get the
following negative test sequence:
TestSeq ) open  deposit  deposit  withdraw
acctSummary  creditLimit  withdraw  close (6.7.45)
Method reversing
In this technique, a method that must be invoked immediately after another method is reversed
with each other to form a negative test sequence. If there are n such pairs of methods, then one can
generate n negative test sequences by this technique. Depending on the methods that are reversed,
it is useful if the class can identify the actual order and report the same.
Method reversing: Example
Let us consider the MtSS of the Account class in equation 6.7.44. In that MtSS, there exists
several pairs that must be invoked in the order of their appearance such as, setupAccnt() - deposit()
and open() - setupAccnt(). By reversing the order of the method invocation, we get negative test
sequences. For example, if we reverse the pair setupAccnt() - deposit() we get the following negative
test sequence:
TestSeq ) open  deposit  setupAccnt  deposit  withdraw
acctSummary  creditLimit  withdraw  close (6.7.46)
Repeating methods
In this technique, a method that must be invoked only once is used multiple times in the sequence
to form a negative test case. Thus, if there are n methods that must be invoked only once, then one
can generate at least n negative test sequences.
Repeating methods: Example
In the MtSS 6.7.44 of the Account class, the method setupAccnt() must appear only once and there-
fore, if it is used more than once, we get a negative test sequence.
TestSeq ) open  setupAccnt  setupAccnt  deposit  withdraw
acctSummary  creditLimit  withdraw  close (6.7.47)
6.7.2 Negative Test Sequences from MgSS
The MgSS of a class de nes a causal order in which a method of a class sends out messages. The
MgSS of a method identi es all possible valid sequences in which the messages are sent out. A
message sequence that is not compliant with the MgSS of a method is thus a negative test case. As
discussed before, we use regular expression formalism to represent the MgSS. The operators used are
'' to represent an immediate sequence, 'j' to represent exclusive-or among sequence, '?' corresponds
to a zero or more number of times repetition, and '+' corresponds to one or more number of times

82
repetition. Even though, several techniques exist for generating various negative test sequences, in
the following, we discuss three techniques for generating negative test cases from MgSS.
Message dropping
In this technique, a message that is a must in any message sequence is dropped. For a given MgSS, if
there are n messages that must appear in every message sequence, then one can generate n negative
test sequences by dropping each message one at a time. Depending on the messages dropped, the
class instances receiving the messages must take di erent corrective actions.
Message dropping: Example
Let us consider the ATM design in gures 6.2 and 6.3. In gure 6.3 several methods of the class
ATM sends out messages to the instances of the Bank and ATM UI class. The method withdraw() of
ATM class sends out messages to Bank class and ATM UI. The MgSS of the method withdraw() is
given below:
withdrawATM ) getCashAmntATM UI  verifyPolicyBank 
withdrawReqBank  dispenseCashATM UI (6.7.48)
The MgSS 6.7.48 represents the causal relation among several messages of the withdraw() method.
In the MgSS, the messages such as getCashAmnt() and verifyPolicy() must appear in every test
sequence generated. By dropping one or more of these messages, one can generate a negative test
sequence. i.e. by dropping the getCashAmnt() message we get the following negative test sequence:
withdrawATM ) verifyPolicyBank  withdrawReqBank 
dispenseCashATM UI (6.7.49)
Message reversing
In this technique, a message that must be sent immediately after another message is reversed with
each other to form a negative test sequence. If there are n such pairs of messages, then one can
generate n negative test sequences by this technique. Depending on the messages that are reversed, it
is useful if the class instances receiving the messages can identify the reversed order of the messages.
Message reversing: Example
Let us consider the MgSS in equation 6.7.48. In this MgSS, there exists several pairs that must be
invoked in the order of their appearance such as, getCashAmnt() - verifyPolicy() and verifyPolicy() -
withdrawReq(). By reversing the order of the message invocation, we get negative test sequences.
For example, if we reverse the pair getCashAmnt() - verifyPolicy() we get the following negative test
sequence:
withdrawATM ) verifyPolicyBank  getCashAmntATM UI 
withdrawReqBank  dispenseCashATM UI (6.7.50)

83
Repeating messages
In this technique, a message that must be sent out only once is used several times in the sequence
to form a negative test case. Thus, if there are n methods that must be sent out only once, then
one can generate at least n negative test sequences.
Repeating messages: Example
Let us consider the MgSS in equation 6.7.48. In this MgSS, messages that must be sent out only
once are getCashAmnt() and verifyPolicy(). By using these messages multiple times we get negative
test sequences. For example, by using the message verifyPolicy() multiple times we get the following
negative test sequence:
withdrawATM ) getCashAmntATM UI  verifyPolicyBank  verifyPolicyBank
withdrawReqBank  dispenseCashATM UI (6.7.51)

84
Chapter 7

Application of OO Testing
Techniques
In this thesis, we have discussed several testing techniques for testing single classes as well as several
classes. In this chapter, we discuss about an application of these testing techniques against a sample
object-oriented program and the results obtained.
We built an ATM simulator in Smalltalk as a target application to subject for applying the
various testing techniques. We evaluated the single class random, partition, data ow, and negative
test cases as well as multiple class random, partition, data ow, and scenario based test cases. In
this chapter, we discuss the results of applying these testing techniques.
The ATM simulator consisted of ve classes: AccountSummary, Account, AccountInfo, Bank, and
ATM. The Account class is for accounts. The Account class used AccountSummary class to store
information about various activities on the account. The AccountInfo class keeps information about
the account, password, policies of withdrawing and so on. The Bank class acts as an interface to
ATM class and bank 'cashier'. It interacts with the Account and AccountInfo class. ATM class is the
interface to account holders for operating their account.

7.1 Class Metrics


All the classes were developed in Smalltalk. The methods in classes can be divided into three
categories: access, support, and transaction methods. The access methods are those that access the
instance variables and modify them. The support methods are those that support the transaction
methods. The transaction methods are those that are available as an interface for methods in other
classes to send messages. The transaction methods use the support and access methods. Sometimes,
the access methods themselves can act as interface methods. In that case transaction methods are
the same as access methods.
In table 7.1, the number of methods in each class under each category is given. From the table, we
observe that, access methods average around 10.6 methods per class. There are not many supporting
methods for each class. Transaction methods vary for each class depending on its usage by other
classes.

85
Class Name Access Support Transaction
AccountSummary 6 0 1
Account 17 4 8
AccountInfo 10 0 0
Bank 11 2 14
ATM 9 1 6

Table 7.1: Number of methods in each class under each category of methods

Class Name Access Support Transaction


AccountSummary 1 0 3
Account 1 9.3 6.6
AccountInfo 1 0 0
Bank 1 5 3.9
ATM 1 2 5

Table 7.2: Average size of methods in each class under each category of methods

In table 7.2, the average size of the methods in each class under each category is given. From the
table, we observe that, access methods average around 1 statement per method in all the classes. The
supporting methods and transaction methods usually have more statements than access methods as
they perform some computation.
In table 7.3, the total faults in each category of methods for each class is given. These faults
are all the faults that were identi ed while testing the ATM-simulator using the testing techniques
proposed in this thesis. From the table, we observe that, not many faults are present in access and
support methods. Most of the faults were in the transaction methods category. Further, most of
the faults were in main classes such as Account and Bank rather than supporting classes such as
AccountInfo and AccountSummary.

Class Name Access Support Transaction


AccountSummary 0 0 0
Account 0 1 17
AccountInfo 0 0 0
Bank 0 0 11
ATM 0 0 1

Table 7.3: Fault density for in each class under each category of methods

86
Testing Technique Account Bank ATM
Random 30 20 10
Partition 26 17 10
Data ow 10 10 10
Negative 18 0 0
Scenario 0 0 6

Table 7.4: Number of test cases generated for each testing technique for classes

7.2 Test Case Execution Order


There exists several dependencies among classes. One can test the classes by bottom-up process in
which the independent classes are tested rst with test drivers and then the dependent classes are
tested. In top-down approach, the top level classes that use many other classes are tested rst with
test stubs and then the independent classes are introduced for testing. In this exercise, we used
bottom-up approach where independent classes were tested rst.
The dependency among classes were that Account class uses AccountSummary class. The Bank
class uses AccountInfo and Account class. The ATM class uses Account class. Thus, the test cases
were executed in the following order: AccountSummary, Account, AccountInfo, Bank, and ATM.
Within each class there are three categories of method types: access, supporting and transaction.
The dependency among methods are, supporting methods use other supporting and access methods.
Transaction methods use supporting and access methods. Thus, the methods were tested in the order
of access methods rst, then supporting and nally sf transaction methods.
The testing techniques for single class testing were used in the order of random testing, partition
testing, data ow testing, and negative testing. For multiple class testing, the sequence was random,
partition, data ow, and scenario based testing techniques. In table 7.4, number of test cases that
were generated to test the transaction methods of each class is given. Negative test cases were not
generated for Bank and ATM.

7.3 Test Case Execution Results


The faults were primarily found in transaction methods rather than access and supporting methods.
To report various kinds of faults, we have developed a simple classi cation scheme. Each fault
category is represented by a number with four digits. The rst digit represents the fault with the
life-cycle phase such as analysis (1), design (2), and implementation (3). The last three digit numbers
identify a speci c fault within a component. The faults that were identi ed in this exercise can be
classi ed into the following categories:
In table 7.6, the faults that were identi ed by random testing for three classes are given.
In table 7.7, the faults that were identi ed by partition testing for two classes is given.
The data ow testing found two faults in Bank class. In category 3332 two faults were identi ed.
The negative testing technique on Account class identi ed three faults related to the category 3412.
The scenario testing on the ATM class identi ed, a fault with a category 3412.

87
Classi cation Category Information
3132 Incorrect domain boundary speci cation
3213 Message not recognized by an object
3214 Incorrect message was received at an object
3221 Incorrect message formation due to parameters
3331 Data ow anomaly due to read before de ne
3332 Data ow anomaly due to de ne and no use
3411 Incorrect implementation, feature misunderstood
3412 Incorrect interaction among methods
3511 Incompleteness, missing feature

Table 7.5: Categories of faults that were recognized during testing

Fault Category Account Bank ATM


3213 7 0 0
3214 1 3 1
3221 1 0 0
3331 1 0 0
3411 0 4 0
3412 2 0 0
3511 1 0 0

Table 7.6: Faults found by Random testing technique

Fault Category Account Bank


3213 1 0
3331 1 0
3411 1 1
3412 1 1

Table 7.7: Faults found by Partition testing technique

88
7.4 Summary
In this chapter, we have discussed about the application of several testing techniques on an example
program. Based on the data collected we can conclude about the simulator program the following.
These conclusions need to be veri ed by applying these techniques against various applications. The
conclusions are:
1. Number of faults identi ed is directly proportional to the number of statements. Classes with
more methods had more faults than the classes with less methods. Therefore, it is evident
that one can develop more reliable code by having less number of statements. This implies
that more reuse of the code would lead to less number of faults.
2. Most of the faults were found in server classes. The client classes that use server classes, did
not have many faults. Thus, those classes that implement the majority of the functionality
must be tested thoroughly compared to those that use those features.
3. Random testing techniques were found to be very useful during initial stages of testing as they
identi ed a large number of faults. Thus, when fault-prone regions are huge, it is cost e ective
to use random testing technique.
4. Partition testing techniques identi ed some of the subtle faults in range checking. Thus, in
classes that is performing a lot of decision making, must be subjected to partition testing
technique.
5. Data ow testing techniques are useful for identifying faults in improper usage of data.
6. Scenario testing techniques are very useful as they increase the con dence with the application.
For variety of scenarios, if the application functions properly, it gives a good con dence about
the application having very less number of faults.
In appendix B, we have included the program code in Smalltalk that was built for the application
of testing technique.

89
Chapter 8

Conclusion
There is an increasing demand for innovative software that satisfy stringent quality and reliability
requirements imposed by users. In recent years OO paradigm is gaining acceptance for developing
complex software. OO paradigm has moved into mainstream software development industry. It is
currently being used in a variety of application development starting from system software such as
databases, operating systems to application software such as banking, billing, and service providing
[12, 66]. The software industry, in general, is moving towards OO paradigm.
The current research so far in OO software engineering is focussed on problem analysis, software
design, and implementation techniques resulting in a potpourri of representations and procedures.
OO analysis methods help in identifying and expressing software requirements in the vocabulary of
classes and objects found in the problem domain. OO design methods facilitate in identifying the
hierarchy among objects and help in depicting both static and dynamic models as well as logical
and physical models of the system. During design, many of the objects and classes identi ed during
analysis are retained and are re ned. OO implementation implements each of the classes and objects
designed that conforms to the static and dynamic models built during design.
Even though the importance of (V&V) is well known, it has commanded little attention in
OO paradigm. A sound software engineering practice is to verify and validate everything that is
developed. Thus, extensive V&V during software development is essential for building zero-defect
software [21]. Unfortunately, most of the OO analysis and design techniques proposed to date do not
adequately address V&V activities. Currently, most of the V&V activities are ad-hoc. If successful
V&V techniques for OO paradigm are not developed, there is a great risk of failure of OO paradigm
as a next-generation software development technique. In this thesis we have addressed the above
issue. We have proposed a set of V&V techniques for OO programs.
In this thesis we have proposed a speci cation based testing technique. The speci cation used in
this thesis is not a complete speci cation for the development of the software, but for representing
the causal relation among various methods of the classes. The speci cation is the key for capturing
information about various classes and used extensively for testing. We have proposed two kinds of
speci cation. The Method Sequence Speci cation (MtSS) of a class documents the correct causal
order in which the methods of the class can be invoked. The Message Sequence Speci cation (MgSS)
of a method documents the causal order in which messages can be sent out to di erent instances of
classes. The MtSS and MgSS of classes document the message-method interaction and the correct
sequence in which messages can ow through a system containing objects. The primary goal of

90
MtSS and MgSS was to facilitate the V&V of classes.
It is important that the speci cation used for testing must be simple, and easy to understand
and develop by the software engineers. Therefore, we have adapted the simple regular expression
formalism to represent the causal representation of methods in a class. In chapter 2 we have discussed
the technique of deriving MtSS of a set of classes from the products of analysis and design. The MtSS
and MgSS is not a complete speci cation of the classes, but captures only those components that
are necessary for V&V. The MtSS and MgSS represents the method interactions, i.e. the dynamic
interactions between the instances of classes. The MtSS and MgSS can be easily incorporated as a
part of many OO analysis and design techniques so that for each class, the sequence speci cation
can be captured. It is also possible to derive the sequence speci cation from OO analysis and design
products. We have rst discussed a technique of deriving MtSS of a class from the corresponding
state based OO design. We have then discussed the derivation of MgSS from Use-case diagrams
[37]. The mapping from these dynamic models to sequence speci cation is well-de ned and most of
the derivation can be automated.
The importance of speci cation Consistency and Completeness (C&C) is well-known in software
engineering. Inconsistency and incompleteness in sequence speci cation would lead to faulty ver-
i cation and therefore, C&C of the speci cation is essential for developing OO systems with less
faults. Since MtSS and MgSS is derived using the analysis and design products of the OO system,
inconsistency and incompleteness identi ed in MtSS and MgSS can be re ected back to the analysis
and design products. Thus, C&C of MtSS and MgSS help in identifying faults in the analysis and
design. In chapter 3, we have provided a set of rules for checking the consistency of MtSS and MgSS
in the presence of single and multiple inheritance. We have then extended the rules to check the
consistency and completeness in the presence of multiple interfaces to a class. These C&C rules can
be easily automated and can be made as a part of OO analysis and design tool software.
An implementation of a OO design must comply with the design. Since the implementation from
design is a manual process, faults can be introduced in OO implementation. In this thesis, we have
proposed several testing techniques to identify faults in the implementation. We have proposed both
static and dynamic testing techniques.
In chapter 5 we have introduced data ow anomaly testing for identifying data ow anomalies
in the implementation. Data ow anomalies are common in programming due to typing mistakes,
copying of the program from one place to other, and so on. A class with a set of methods, is
reusable in all situations, if the class can be tested extensively with all valid combinations of method
invocations. A class does not indicate the sequence in which methods can be invoked. Therefore,
we use the MtSS of the class to determine the sequence among a set of methods. Once the sequence
among methods is known, all the conventional anomaly detection techniques can be applied. In that
chapter, we have illustrated the application of data ow anomaly detection with an example.
A program with absence of data ow anomalies might still contain variety of faults. Therefore, we
need dynamic testing techniques that execute the software against a test case. In this thesis, we have
discussed di erent dynamic testing techniques including random, partition, data- ow, and scenario
based testing (see chapter 6). We have discussed about test case generation from single class, several
classes, and state-transition diagram of the class instances. These testing techniques can be used
for unit testing or integration testing. All the testing techniques use the sequence speci cation for
generating test sequences. The test sequences not only help in testing of the program, but also
helps in understanding of the class behavior. All the above testing techniques are for ensuring the
correctness of OO programs. We have also introduced a testing technique for ensuring the robustness

91
of a class. In this testing technique (also known as dirty testing technique), we have introduced a
methodical way of generating illegal sequences that can be used to test the classes. The class instance
must identify such illegal sequences and notify the user of the class about the improper usage.
Even with extensive testing, an implementation might not reveal all the out-of-sequence messages
to instances of a class. In this thesis, we have proposed a run-time veri cation system that checks for
the consistency of messages received at each object with respect to its sequence speci cation and ags
out out-of-sequence messages. This kind of run-time veri cation is very essential in safety-critical
systems[53]. The run-time veri cation system maintains the sequence speci cation as a part of the
class structure. All the class instances keep track of the messages they receive and compare against
the sequence speci cation to ensure that the objects are receiving the methods in correct order.
We have provided a data structure design of a possible implementation of the run-time veri cation
system.
In this thesis, we have discussed several test case generation techniques. We applied several of
these testing techniques to an example OO program. An ATM simulator was built in Smalltalk and
was subjected to testing. The results collected are very promising. However, one has to apply these
techniques for several other applications and determine their applicability.
In this thesis we have introduced several testing techniques for test case generation. Further
research in V&V of OO systems will continue to introduce new testing techniques. These testing
techniques vary in their e ectiveness, robustness, and cost. Some of these testing techniques may
be useful during the initial stages of testing while some of them may be useful only for identifying
faults in the implementation. Thus, from the practitioner's point of view it is often necessary to
determine comparative merits and demerits of these testing techniques. In this thesis, we have
proposed a testing technique evaluation methodology based on life cycle mutation testing. This
evaluation scheme facilitates the evaluation of various testing techniques. We have applied the
above methodology for a set of testinging techniques evaluation in the context of expert system
testing. The application of the above methodology is independent of the development paradigm and
therefore can be easily applied to OO paradigm.

8.1 Research Directions


This thesis on Veri cation and Validation of OO programs opens up a set of new research issues. In
this thesis, we have concentrated on a speci cation technique and how one can use the speci cation
to generate test cases for testing an OO program. The techniques that we have proposed in this
thesis is in not a all-inclusive set. However, it provides a good start for various V&V related research
issues. In the following we brie y discuss about the related research issues.
(1) Reliability Models: Software reliability models for OO systems is a research topic that requires
more attention. Reliability models help in estimating the fault density in OO systems and thus can
help in estimating time and resources required for testing. Reliability models play an important role
for highly critical applications such as nuclear reactor control, space vehicle, and medical control
instruments applications as the models help in estimating the quality of the software. The reliability
models also help when to stop testing.
To build the reliability models for OO, one has to apply many of the testing techniques to
di erent applications and measure data over a period. As OO applications are getting developed
now, it will be some time before we can see some reliability models.
(2) Integration of V&V with Analysis and Design: For developing OO applications, many OO

92
analysis and design techniques have been proposed. Most of these techniques does not address the
issue of V&V in analysis and design products. It is important that analysis and design products
are consistent and complete and are subjected to extensive V&V. In this thesis we have proposed
several techniques that can be used for checking the consistency and completeness. The research
issue is to map the sequence speci cation technique used in this thesis with the OO analysis and
design techniques so that all the V&V techniques that use sequence speci cation can be adapted.
(3) Inspections and Walkthroughs: In conventional paradigm, it has been shown in several studies
that inspections and walkthroughs assist in identifying faults early and thus improving the quality of
the software applications. Inspections and walkthroughs have been applied to requirements, design,
and code in conventional paradigm. In many of the studies, the nal program (code) is the target.
The program in procedural world was easy to walkthrough as the execution ow can be determined
statically. However, in OO paradigm, the code interacts more dynamically and often dicult to
statically determine the execution ow. Therefore, new techniques and tool support is essential for
performing walkthroughs through an OO design or program.
Similarly, the inspection lists that have been used for years must be updated to accommodate new
features in OO paradigm. The cost analysis of inspections and walkthroughs for OO applications is
also very useful.
(4) Testing Classes for Reusability: It is believed that OO paradigm facilitates the resuability
of the nal code in the form of classes, design byproducts and analysis information. The reusable
library of classes is common in OO software development environment such as GUI building and
database connection support. The domain based classes or classes developed for solving particular
tasks in an organization can be reused in various applications. This is possible, if classes are tested
thoroughly for its usage in all possible cases rather than a particular case of its use in an application.
In this thesis, we use the sequence speci cation to identify all possible combinations of method
sequences in which an instance of a class can be invoked. The research issue is to generate test
cases for reusability of the class using the techniques presented in this thesis along with the domain
information of classes.
(5) Testing Techniques for Distributed OO systems: In recent years, there is a need for running
applications in a distributed environment due to the increasing demand for throughput, high vol-
ume of database support, resilience and redundancy in the systems and so on. Several techniques
and run-time support exist today for distributing objects over a network of computers and allow
transparent interaction among those objects. For example, the CORBA (Common Object Request
Broker Architecture) from OMG is a standard for such a distribution. OO software in a distributed
environment, introduces new issues for testing due to concurrency, reliability, administration, and
security.
(6) Fault Taxonomy for OO paradigm: The fault taxonomy for software is important as it
provides several valuable information such as frequency, type of fault, correction cost, installation
cost and possible consequences [6]. The fault taxonomy available in [6] does not contain new kinds
of faults possible in OO paradigm. Further the classi cation of di erent kinds of faults may not be
applicable in OO paradigm. Therefore the research issue is to identify and classify di erent kinds
of faults possible in OO software. A fault taxonomy for OO help in metrics collection, reliability
models and many other research work.
(7) Using run-time information for better test case generation: In this thesis, we have discussed
about several testing techniques that use only static information for test case generation. The OO
programs are dynamic in nature and many of the execution paths can be determined only during

93
run-time. Therefore, one has to investigate the techniques of capturing information during run-time
and use that information for test case generation.
(8) Tool support for testing activities: In software testing, test case generation is the most
expensive activity. However, for successful testing, one has to manage the generation of test cases,
execution of the test cases, and evaluation of test results. A tool support for automating many
of these activities is useful for reducing the cost of testing. Further, the test case designs and
traceability of test cases with respect to actual design and code is important so that when designs
and program change, the test cases can also be changed.

94
Bibliography
[1] A. V. Aho, R. Sethi, and J. D. Ullman. Compilers: Principles, Techniques, and Tools. Addison-
Wesley Publishing Company, 1986.
[2] T. R. Arnold and W. A. Fuson. Testing In a Perfect World. CACM, 37(9):78{86, September
1994.
[3] J. Bachant. R1 revisited: Four years in the trenches. AI Magazine, pages 21{32, Fall 1984.
[4] F. B. Bastani. Reliability of AI programs. In B. W. Wah and C. V. Ramamoorthy, editors,
Computers for Arti cial Intelligence Processing, pages 532{562. John wiley & Sons, New York,
New York, 1990.
[5] F. B. Bastani and I. R. Chen. Assessment of reliability of AI programs. Proc. of IEEE Inter-
national Conference on Tools for AI, pages 753{759, 1990.
[6] B. Beizer. Software Testing Techniques. Van Nostrand Reinhold, second edition, 1990.
[7] R. V. Binder. Design for testability. CACM, 37(9):89{101, September 1994.
[8] R. V. Binder. Testing object-oriented systems: A status report. American Programmer, 7(4):23{
28, April 1994.
[9] B. W. Boehm. The high cost of software. In Ellis Horowitz, editor, Practical Strategies for
Developing Large Software Systems. Addison-WesleY, 1975.
[10] B. W. Boehm. Verifying and validating software requirement speci cations and design speci -
cation. IEEE Software, 1:61{72, 1984.
[11] B. W. Boehm. A spiral model of software development and enhancement. IEEE Computer,
21(5):61{72, May 1988.
[12] G. Booch. Object-Oriented Analysis and Design with Applications. The Benjamin/Cummings
Publishing Company, Inc., second edition, 1993.
[13] F. P. Brooks. No silver bullet, essence and accidents of software engineering. IEEE Computer,
20(4):10{19, April 1989.
[14] T. J. Cheatham and L. Mellinger. Testing object-oriented systems. In Proceedings of the 18Th
ACM annual Computer Science Conference, pages 161{165. ACM Inc., New York, 1990.

95
[15] S. Chidamber and C. Kemerer. Towards a metrics suite for object-oriented design. In OOPSLA,
1991.
[16] S. Chidamber and C. Kemerer. A metrics suite for object-oriented design. Technical report,
Sloan School of Management, MIT, 1993.
[17] P. Coad and J. Nicola. Object-Oriented Programming. Yourdon Press, 1993.
[18] P. Coad and E. Yourdon. Object-Oriented Analysis. Yourdon Press, Prentice Hall, Englewood
Cli s, NJ, second edition, 1991.
[19] J. M. Drake, W. W. Xie, and W. T. Tsai. Document-driven analysis: Description and formal-
ization. Journal of Object-Oriented Programming, pages 33{50, November 1992.
[20] J. W. Duran and S. C. Ntafos. An evaluation of random testing. IEEE Transacitons on Software
Engineering, SE-10(4):438{444, 1984.
[21] M. Dyer. The Cleanroom Approach to Quality Software Development. John Wiley & Sons, Inc.,
1992.
[22] M. Ellis and B. Stroustrup. The Annotated C++ Reference Manual. Addison-Wesley, Reading,
Massachusetts, 1990.
[23] M. E. Fagan. Design and code inspections to reduce errors in program development. IBM
Systems Journal, 3:182{211, 1976.
[24] J. E. Fetzer, editor. Aspects of Arti cial Intelligence, pages 209{250. Kluwer Academic Pub-
lishing, 1988.
[25] S. P. Fielder. Object-oriented unit testing. Hewlett-Packard Journal, pages 69{74, April 1989.
[26] L. D. Fosdick and L. J. Osterweil. Data ow analysis in software reliability. ACM Computing
Surveys, Septmber 1976.
[27] P. G. Frankl and R. Doong. Tools for testing object-oriented programs. In Proceedings of the
Paci c Northwest Software Quality Conference, pages 309{324, 1990.
[28] A. Goldberg and D. Robson. Smalltalk-80: The Language and Its Implementation. Addison-
Wesley, 1983.
[29] B. Hailpern and H. Ossher. Extending objects to support multiple interfaces and access control.
IEEE Transactions on Software Engineering, 16(11):1247{1257, November 1990.
[30] M. J. Harrold, J. D. McGregor, and K. J. Fitzpatrick. Incremental testing of object-oriented
class structures. In International Conference on Software Engineering, pages 68{80. ACM Inc.,
New York, 1992.
[31] M. S. Hecht. Flow Analysis of Computer Programs. North-Holland, New York, 1977.
[32] D. M. Ho man and P. A. Strooper. A case study in class testing. In Proceedings of CASCON-93,
pages 472{482. IBM Toronto, 1993.

96
[33] L. H. Holley and B. K. Rosen. Quali ed data ow problems. IEEE Transactions on Software
Engineering, SE-7:60{78, Jan 1981.
[34] J. E. Hopcroft and J. D. Ullman. Introduction to Automata Theory, Languages, and Computa-
tion. Addison-Wesley Publishing Company, 1979.
[35] J. C. Huang. Detection of data ow anomaly through program instrumentation. IEEE Trans-
actions on Software Engineering, SE-5:226{236, May 1979.
[36] J. Jachner and V. K. Agarwal. Data ow anomaly detection. IEEE Transactions on Software
Engineering, SE-10(4):432{437, July 1984.
[37] I. Jacobson, M. Christerson, P. Jonsson, and G. Overgaard. Object-Oriented Software Engi-
neering. Addison-Wesley Publishing, Workingham, England, 1992.
[38] P. C. Jorgenson and C. Erickson. Object-oriented integration testing. CACM, 37(9):30{38,
September 1994.
[39] T. F. Keefe, W. T. Tsai, and M. B. Thuraisingham. Soda: A secure object-oriented database
system. Computers and Security, 8(6):517{533, 1989.
[40] S. Kirani. Speci cation and Veri cation of Object-Oriented Programs. PhD thesis, University
of Minnesota, December 1994.
[41] S. Kirani, I. A. Zualkernan, and W. T. Tsai. Evaluation of expert system testing methods.
Communications of the ACM, pages 71{81, november 1994.
[42] H. J. Lee and W. T. Tsai. A new partial inheritance mechanism and its applications. Technical
Report TR:92-17, University of Minnesota, Computer Science Department, Minneapolis, MN-
55455, 1992.
[43] Y. Levendel. Improving quality with a manufacturing process. IEEE Software, pages 65{79,
March 1991.
[44] M. Lijter, S. Meyers, and S. P. Reiss. Support for maintaining object oriented programs. IEEE
Transactions on Software Engineering, 18(12):1045{1052, December 1992.
[45] S. B. Lippman. C++ Primer. Addison-Wesley Publishing Company, second edition, 1991.
[46] P. S. Loo, W. T. Tsai, and W. K. Tsai. Random testing revisited. Information and Software
Technology, 30(7):402{417, 1989.
[47] J. Martin. Principles of Object-Oriented Analysis and Design. P T R Prentice Hall, 1993.
[48] J. Martin and W. T. Tsai. N-Fold inspection: A requirement analysis technique. Communica-
tions of ACM, 33(2):225{232, 1989.
[49] R. McDaniel and J. D. McGregor. Testing the polymorphic interactions of classes. Technical
Report TR:94-103, Clemson University, 1994.
[50] J. D. McGregor and T. D. Korson. Integrating object-oriented testing and development pro-
cesses. CACM, 37(9):59{77, September 1994.

97
[51] B. Meyer. Object-oriented Software Construction. Prentice Hall International, 1988.
[52] B. Meyer. Applying design by contract. COMPUTER, pages 40{51, October 1992.
[53] R. Mojdehbakhsh, W. T. Tsai, S. Kirani, and L. Elliott. Retro tting software safety in an
implantable medical device. IEEE Software, pages 41{50, January 1994.
[54] D. E. Monarchi and G. I. Puhr. A research typology for object-oriented analysis and design.
Communications of the ACM, 35(9):35{47, September 1992.
[55] G. C. Murphy, P. Townsend, and P. S. Wong. Experiences with cluster and class testing. CACM,
37(9):39{47, September 1994.
[56] J. Musa, A. Iannino, and K. Okumoto. Software Reliability: Measurement, Prediction, Appli-
cation. McGraw-Hill, New York, New York, 1987.
[57] G. Myers. The Art of Software Testing. Prentice Hall, 1979.
[58] J. A. Naser. Nuclear power plant expert system veri cation and validation. In U. G. Gupta, ed-
itor, Validating and Verifying Knowledge-based Systems, pages 26{41. IEEE Computer Society
Press, 1991.
[59] NeXT Inc. Reference to NeXTSTEP Programming Objects, 1989.
[60] S. Ntafos. On required element testing. IEEE Transactions on Software Engineering, SE-
10(6):795{803, 1984.
[61] M. A. Ould and C. Unwin. Testing in Software Development. Cambridge University Press,
1987.
[62] D. E. Perri and G. E. Kaiser. Adequate testing and object-oriented programming. Journal of
Object-Oriented Programming, pages 13{19, January/February 1990.
[63] R. M. Poston. Automated testing from object models. CACM, 37(9):48{58, September 1994.
[64] S. Rapps and E. J. Weyuker. Selecting software test data using data ow information. IEEE
Transactions on Software Engineering, SE-11(4):367{375, 1985.
[65] W. W. Royce. Managing the development of large software systems: Concepts and techniques.
Proc. of WESCON, pages 1{9, 1970.
[66] J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, and W. Lorensen. Object-Oriented Modeling
and Design. Prentice Hall, Englewood Cli s, NJ, 1991.
[67] S. Sankar and R. Hayes. ADL-an interface de nition language for specifying and testing soft-
ware. In Proceedings of the Workshop on Interface De nition Languages, pages 13{21, 1994.
[68] M. D. Smith and D. J. Robson. Object-oriented programming - the problems of validation. In
IEEE Conference on Software Maintenance, pages 272{281, 1990.
[69] M. D. Smith and D. J. Robson. A framework for testing object-oriented programs. Jouranl of
Object-Oriented Programming, 5(3):45{53, 1992.

98
[70] A. Snyder. Encapsulation and inheritance in object-oriented programming languages. In Stan-
ley B. Xdonik and David Maier, editors, Readings in Object-Oriented database systems, pages
84{91. Morgan Kaufmann Publishers, Inc, 1986.
[71] A. Spector and D. Gi ord. Case study: The space shuttle primary computer system. Commu-
nications of the ACM, 27(9):872{900, September 1984.
[72] S. Subramanian, W. T. Tsai, and S. Kirani. Hierarchical data ow analysis for oo programs.
Journal of Object-Oriented Programming, 7(2):36{46, 1994.
[73] C. D. Turner and D. J. Robson. The testing of object-oriented programs. Technical Report
TR-13/92, University of Durham, Computer Science Division, SECS, Durham, England, 1992.
[74] M. A. Vouk, D. F. McAllister, and K. C. Tai. An experimental evaluation of the e ectiveness of
random testing of fault-tolerant software. In Proceedings of the Workshop on Software Testing
Conference, pages 74{81, 1986.
[75] D. M. Weiss and V. R. Basili. Evaluating software development by analysis of changes: some
data from the software engineering laboratory. IEEE Transactions on Software Engineering,
11(2):157{168, 1985.
[76] R. J. Wirfs-Brock and R. E. Johnson. Surveying current research in object-oriented design.
CACM, 33(9):104{124, september 1990.
[77] R. J. Wirfs-Brock, B. Wilkerson, and L. Wiener. Designing Object-Oriented Software. Prentice
Hall, Englewood Cli s, New Jersey 07632, 1990.
[78] R. W. Wolverton. The cost of developing large scale software. In Ellis Horowitz, editor, Practical
Strategies for Developing Large Software Systems. Addison-Wesley, 1975.
[79] I. A. Zualkernan, W. T. Tsai, A. Jemie, I. C. Wen, and J. M. Drake. Object-oriented anal-
ysis as design: A case study. International Journal on Software Engineering and Knowledge
Engineering, 2(4):489{521, 1992.

99

You might also like