Professional Documents
Culture Documents
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 Verication and Validation (V&V) is
known, it has commanded little attention in OO paradigm.
In this thesis1 we propose a new specication technique called Method and Message Sequence
Specication that represents the causal relationship between the instance methods of a set of classes.
The Method Sequence Specication (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 Specication (MgSS)
of a set of classes documents the causal order in which messages can be sent to instances of dier-
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 specication 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 specication 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 verication 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 Benets 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 Specication 15
2.1 Method Sequence Specication (MtSS) : : : : : : : : : : : : : : : : : : : : : : : : : : 16
2.1.1 Properties satised 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 Specication (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 Renement 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 Verication 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 Renement Inheritance and Anomaly Detection : : : : : : : : : : : : : : : : : 55
5.4.3 Implementation Inheritance and Anomaly Detection : : : : : : : : : : : : : : 56
5.5 Conclusion : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : 56
6 Test Case Generation from Specication 57
6.1 Introduction to Test Case Generation : : : : : : : : : : : : : : : : : : : : : : : : : : 58
6.1.1 Identication 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 Verication 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 Renement Inheritance : : : : : : : : : : : : : : : : : : : : : : 31
3.2 Specication and Verication of Counter Design : : : : : : : : : : : : : : : : : : : : : 32
3.3 Example Illustrating Multiple Interfaces of Account Class : : : : : : : : : : : : : : : 35
4.1 An example for illustrating verication of implementation against the specication. : 38
4.2 Data structure diagram for implementing run-time verication 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 specication 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
identied during analysis are retained and are rened. 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 Verication 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 specication technique called Method and Message
Sequence Specication that represents the causal relationship between the instance methods of a set
of classes. The Method Sequence Specication (MtSS) of a class documents the correct causal order
in which the methods of the class can be invoked. The Message Sequence Specication (MgSS) of
a set of classes documents the causal order in which messages can be sent out to dierent 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 specication.
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 specication of the
2
OO Analysis
OO Specification
Internal C&C
OO Source Code
OO
Implementation
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 specication. It is also possible to derive the sequence specication 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 specication Consistency and Completeness (C&C) is well-known in software
engineering. Inconsistency and incompleteness in sequence specication would lead to faulty ver-
ication and therefore, C&C of the specication 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 identied 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 verication
system that checks for the consistency of messages received at each object with respect to its sequence
specication and
ags out out-of-sequence messages. A support for run-time verication 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 eectiveness, 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 eective.
In the rest of this chapter we discuss about OO as well as V&V related concepts.
4
Object, class, and structure
Identification
Individual
classes
OOA OOA
OOT OOT
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 dierent sets of messages. Even though a class denes 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 redened by a subclass, nullifying the inherited denition. 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 Benets 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 rened 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 dierent objects. Further, the state of the application is distributed
and encapsulated in dierent objects. Thus, to get a proper understanding, testing, and debugging
of the system, tracing of the methods and messages is essential.
6
Requirement Analysis
and Design Coding Testing
Specification
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 specication, testing is ill-dened.
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 specied in the problem specication 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 specication is
a measure of the portion of the specication implemented in the system. A system is complete
if it covers all the problems indicated in the problem specication.
Robustness: Robustness is the extent to which a software system deteriorates gracefully at
the limits specied in the problem specication. Hence, robustness determines how a system
handles problems that are outside its denition. A system has high robustness if it degrades
gracefully for problems not specied in the problem specication. 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 specication,
and its solution specication 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.
Identication 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 oers 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)
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 specication in the problem spec-
ication or requirements document. When possible input and output spaces are large, determining
legal inputs and outputs may be dicult. Although a problem specication 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 eectively generate a test input when problem specication does not specify
the denition of a legal input. If the problem specication species 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
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 sacricing 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-
eect graph testing, ablation testing, inspection and walkthroughs, auto-regressive testing. Each of
these methods species 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 eective on larger programs (or large sample space to select test cases)
that are more sensitive to special values [74]. For random testing to be eective 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 specication 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
dierent 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 eective 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-eect 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 specication. The path based partition test-
ing is usually limited by the availability of clear solution specication 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 eective for checking whether the program faithfully follows its design. A disadvantage of this
technique is that the eort is proportional to the number of paths in the design.
Cause-eect graph testing
Cause-eect graph testing uses solution specication 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) specications and
implementation. The exhaustive nature of this testing makes it particularly eective for detecting
unanticipated side eects [57]. This type of testing can also be used to demonstrate the quality of
the solution specication. However, for a large software system the cost of cause-eect 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-eect
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 dene and use of a
data value. Data
ow testing tests all paths between such a dene-use (DU) pair. There exists
dierent 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 dene to its use in a calculation.
All-p-uses: All the paths from a variable dene 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 dene 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 eective 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 dierent 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 condence 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.
13
testing, (2) Specication 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 specications of the classes is discussed in [27]. In [67], authors
use assertion denition 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 eective.
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
15
of the class and everything an implementor should know for proper implementation of the class.
Even though the complete contract specication 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 verication 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 specication 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].
Denition 2.1 Methods(C): For a class C we dene Methods(C ) as a set of all the instance meth-
ods dened in C that are publicly available.
Example: For a Stack class the method set can be, Methods(Stack) = fpush, pop, isempty?, isfull?,
top g
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 specication of a class C we use regular denition over the
alphabet (usually referred as ) consisting of methods from Methods(C ). The regular denition is
a set of denitions 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 denition associated with a class denes all the valid method sequences that the object can
invoke.
Denition 2.2 Method Sequence: We dene 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.
Denition 2.3 SeqSpec(C ): A SeqSpec(C ) is the specication of C that denes a sequence rela-
tionship between all the methods of C . We use regular denition for specifying the SeqSpec(C ). We
also use REC to refer to regular denition.
Example: Let us consider a specication of a simple bank account class as shown in gure 2.1. The
interface methods dened 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 specication,
the regular denition 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( )
In the above sequence specication (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.
Denition 2.4 SafeSeq(C ): A SafeSeq(C ) denes 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) dened by
SeqSpec(C ).
Example: The sequence specication of Account class given in the previous example denes 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 satised by MtSS
In this section, we give a set of properties satised by any MtSS of a class. These properties are
derived from regular denitions 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.
19
Withdraw ( )
Operation Deposit ( )
Account
Deposit ( )
Open ( ) Empty
Start Account Close ( )
Null
Account
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 classied 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 prex sequence number.
The prex 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 prexed 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
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 modied 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.
22
o2:C2
m2
m1 m3
o1:C1 o3:C3
m4
o4:C4
The MgSS is specied for each of the method that sends out messages. MgSS and MtSS together
can identify the causal order between any two methods dened in two dierent 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 identies all the messages it sends out to other domain objects. It also
identies the causal order in which the messages are sent out. For the MgSS specication 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 prexed 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 dierent scenarios lead to dierent 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 identied. These blocks are represented by a vertical
column in the Interaction diagram. A special column is shown dierently 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
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
dierent classes and the causal order among them is identied.
26
Chapter 3
27
parent and child class specication may be inconsistent with one another and therefore consistency
verication between the parent and child class specication 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.
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.,
Denition 3.4 NewMethods(Ck): A set of methods that are newly added in class Ck and not
inherited from the parent classes of Ck .
Denition 3.5 InhMethods(Ck; Ci ): A set of methods of class Ck that are inherited from class Ci
6 Ci.
and Ck =
Denition 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 veries 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 modied, 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 dierence 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 modied 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 specication 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 Renement Inheritance and MtSS
In renement inheritance, the child class modies the semantics of some of the inherited methods
from the parent classes. Modications 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 dierent results for the same set of
inputs. For representing the methods that are rened in the child class we dene the following term.
Denition 3.7 RefMethods(Ck; Ci): A set of methods in Ck inherited from Ci, whose implemen-
tation are modied.
C&C of MtSS of the parent and child classes that are related through renement inheritance is
similar to the one described in section 3.1.1. The dierence is in the computation of the set Si. For
30
Account
Methods: Open, Close, Deposit, WIthdraw
Create, and Destroy
the C&C rule in the case of renement inheritance, the Si must include the RefMethods(Ck; Ci)
where i = 1; : : : ; k ; 1. Informally, the inherited methods that are rened 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 rened 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 rened. The ParentMtSSC is the MtSS of the parent class containing
i
only those methods that are not rened in the child class. For the consistency rule, these two MtSS
must be equal.
Renement inheritance: Example
In gure 3.1, the child class Savings Acc renes some of the methods inherited from the parent class
Account. The methods Deposit and Withdraw of the parent class are modied to compute interest.
The specication of child class can be veried 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 modied. 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
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 dierence 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 renement inheritance. The IntegerCount class enhances the inherited class with a new method
asBase. All the child classes rene the methods increment and decrement, but do not change the
protocol of them. The sequence specication of Count class is,
Methods ! Count DataSetup Operations Count
DataSetup ! set value set reset value
Operations ! (increment decrement reset)
32
In the above sequence specication, 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 specication must be
modied. But, the goal of the above specication 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 specication 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 specications of IntegerCount and Count can be veried 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 specication 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 benecial
when an inheritance tree grows in depth.
The additional advantage of the above specication is that it helps to understand the interface
of a class. The sequence specication clearly species the sequencing information which is useful
during program development so that the class can be used correctly.
33
methods must be consistent. In the following we model the multiple subinterfaces and dene the
consistency rule that the sequence specication of all subinterfaces must follow.
3.2.1 C&C of MtSS with Multiple Interfaces
For a given class C , let, I1 ; : : : ; Ik be dierent subinterfaces the class supports. In the following we
dene some more terms that are useful for dening the rule.
Denition 3.8 Methods(Ii; C ): The Methods(Ii; C ) denes a set of methods of class C that are
available to subinterface Ii . This is also denoted by i .
Denition 3.9 SeqSpec(Ii; C ): SeqSpec(Ii; C ) denes the MtSS for the subinterface Ii of class C .
From the above denitions 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 specication for each subinterface Ii by a regular expression
MtSSi.
Informally, the consistency rule is that the sequence specication 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
specication must satisfy.
Rule 3.5 Let I ; : : : ; Ik , be the subinterfaces of class C ,
1
MtSS ; : : : ; MtSSk be the corresponding sequence specication 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 veried 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.
34
Account Manager
Create
CompInterest interface
GenReport
ChangeAddress Officer
Close
Delete
Open
Deposit
Withdraw Owner
Balance
syntax. A regular expression denes a well-dened 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 denes a Finite Automata (FA). A FA accepts a set of strings
and all the acceptable strings form the language dened 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].
35
1) m1 is inherited under specialization inheritance, or
2) m1 is inherited under renement inheritance and m1 is not modied, 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 modied 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 modied.
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 dierent 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 specications 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 species the correct sequence in which messages can be sent to instances of the class.
Similarly, the MgSS species 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 species 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. Specically, 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 modications 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 specication. However, this verication depends on the result of control
ow analysis in
identifying all the use sequences. In this chapter, we stress on verication 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
Withdraw 6
bar
7
Client C
Figure 4.1: An example for illustrating verication of implementation against the specication.
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.
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 verication system
class. For each invocation of the method, the verication system checks for the sequence consistency
with respect to the stored sequence specication. If the method invoked is not compliant with the
specication, then an exception is raised and control is transferred to an exception handler.
The run-time verication system determines sequence correctness by checking the method se-
quence with the regular denition of the MtSS. To specify the causal order among methods, MtSS
uses regular expression language operators such as '', 'j', '?', and '+'. The verication of use se-
quences with respect to the MtSS is similarly to checking whether a string is part of a regular
denition. 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 verication 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
verier code is kept. All the method invocations are processed rst by the sequence verier. The
sequence verier checks each invoked method with the MtSS for correctness. the sequence specier
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 verication system can be used in
39
SmallTalk implementations as its run-time structure is open for modication.
40
Chapter 5
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 dene 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.
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
43
2. dd: This combination may be harmless but suspicious as the variable is dened twice without
an in between use. In the above example, in line 8 and 9, the variable err is dened 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 dened, 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 undened 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. Dierent 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 satised:
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.
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 identied 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-dened 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 specication 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 specication 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 specication. 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
A j B - The regular expression operator 'j' represents an 'OR' operator between two methods in a
sequence specication 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 specication 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 dierent 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 specication
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 specication
corresponding to this behavior of the Account class is,
50
open
deposit
n1
deposit withdraw
deposit
withdraw
withdraw withdraw
deposit
deposit
n2
close
Figure 5.4: Control Flow Graph representation of the sequence specication of \Account" Class.
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 identied by the technique we have discussed
in this chapter. However, the conventional techniques, if applied directly, cannot determine such
data
ow anomalies.
52
SequenceableCollection
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 denitions that we use while discussing this section.
Denition 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 .
Denition 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 =
Denition 5.3 Vn (C ): A set of instance variables that are newly introduced in class C .
Denition 5.4 Vo (C ): A set of all the instance variables that are dened in all the parent classes
of class C .
Denition 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 specication of all the methods
in class Ck .
53
Account Methods: open, deposit, withdraw, close
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 specication 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.
55
parent and child class that are related through inheritance, thus may produce dierent results for
the same set of inputs.
In renement inheritance, the inherited methods are modied 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 dened in parent classes, is similar to the
one described in the previous section. i.e. For new instance variables, only those methods that are
rened are considered. Further, if all the rened 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 dened 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 modied. 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 specication 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 specication and an imple-
mentation that is free from bugs compliant with the specication 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 specication 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 specication. 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
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
eective in identifying most of the faults in a program.
Test cases are usually generated in three steps.
1. Identication 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. Specication of test inputs and the state of related components that exercise the components
selected in the previous step.
3. Specication 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 dened 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 Identication 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 dierent 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 dened classes such as menus, windows,
buttons, and scroll-bars. These reusable classes are used in dierent applications under dierent
contexts. These classes might support several methods for dierent 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 identied 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 identied, 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 specication of the component. Test inputs can be generated automatically, if the specication
is well dened and rigorous. For example, test inputs to test a compiler can be usually generated
from the grammar specication 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
specication based test cases, input and expected output can be generated from the specication.
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 dened 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, specication of input and output states are involving. The specication of the state
of objects is more dicult when multiple objects are selected as target components for testing.
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 dene-use pairs of
the data that dene a sub-path in a method. The number of dene-use pairs again can be
very large and these pairs can be ltered based on a specication.
State-based Test case generation: A method can change the state of an object based on dierent
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 benet 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 modied 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 dened, the testing history of the parent
class and the modications 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.
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 specication 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.
61
open ( )
setupAccnt ( )
deposit ( )
withdraw ( )
Account
acctSummary ( ) Class
balance ( )
creditLimit ( )
close ( )
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 eective, 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 innitely 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 satises 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.
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 eort 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 eective. By combining the domain information and the sequence specication, 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 specication and a good partition
criteria. Partition testing is found to be eective 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 innite.
The transaction methods in the MtSS 6.4.7 can be split into partitions using a partition criteria.
In the following we discuss dierent 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 aecting 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 aecting 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
dierent 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 aecting 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 classied as follows:
Transaction ) (UsejModifyjNoAccess)? (6.4.12)
Use ! (depositjwithdrawjcreditLimit) (6.4.13)
Modify ! (depositjwithdraw) (6.4.14)
NoAccess ! (balancejacctSummary) (6.4.15)
From the dierent 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 dierent 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 dierent 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 eectiveness of partition based test cases depend on the eectiveness of the partitioning
criteria. Partition based test cases are eective 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 dierent 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. Dierent strategies can be derived based on dene, 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 dene, use, and modify the instance variables of the class. The instance variables
are global to all the methods dened 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 dierent test cases depending on this data
ow.
In data
ow test case generation, the rst step is to identify a dene and use pair of a data value.
In OO, that corresponds to nding out the methods that dene and use an instance variable. Then
a test method sequence can be generated such that it contains the method that denes the variable
as well as the one that uses the variable. There can be more than one method that denes and uses
the same instance variable. Similarly, within a method, an instance variable can be dened or used
more than once. For dening 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 denes 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 dene 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;
...
}
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 dening 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 dene and use the data.
Thus, there can exist many dene-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 denition 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 denition free minimal sequence of methods from every denition of every variable to every
use of the variable. Similarly the above strategies can be extended with all-denitions-sequence, all-
predicate-use-sequences, and all-computational-use-sequences.
70
cardInserted
password
deposit
withdraw
accntStatus
ATM operations
terminate
ATM UI ATM
verifyStatus
depositStatus Bank Class
dispenseCash
print accnt stat
readCardInfo
getCashAmnt
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
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 identies all the messages it sends out to other
objects. It also identies the causal order in which the messages are sent out. The MgSS specication
uses the regular expression formalism. In addition to the operators ' ', 'j', '+', and '*' we use a new
operator '?' that indicates that a message prexed 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 dierent
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 innite 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
dene-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. Identication of the domain data that is read, dened, used, and computed across class in-
stances.
2. Identication of the criteria of data access such as dene-use, read-use, or create-use of the
domain data.
3. Identication of a sequence of methods belonging to dierent classes that links up the method
that denes 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 aects 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 dierent class instances form a data
ow test case. From
the perspective of ATM UI, the method deposit() denes 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 denes the data and in equation 6.5.31 a method sequence
uses the data that was dened 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 identied. 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 specication 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 specication 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 specication of the methods supported by the Bank class in equa-
tion 6.5.32. We can partition the transaction methods into state aecting and non state aecting.
The state aecting methods are depositReq() and withdrawReq() while the non state aecting method
is acctInfoReq(). A test case generated from the non-state aecting 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 dened. 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 dened 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.
78
Empty
open
Accnt
setupAccnt
Setup
deposit
Accnt
deposit
withdraw
Working Non
withdraw
Accnt working
balance
credit close
accntInfo
Dead
Accnt
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 satises
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.
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 denes a causal order in which a method of a class sends out messages. The
MgSS of a method identies 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 dierent 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.
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
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 identied 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.
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
87
Classication Category Information
3132 Incorrect domain boundary specication
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 dene
3332 Data
ow anomaly due to dene and no use
3411 Incorrect implementation, feature misunderstood
3412 Incorrect interaction among methods
3511 Incompleteness, missing feature
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 veried by applying these techniques against various applications. The
conclusions are:
1. Number of faults identied 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
identied a large number of faults. Thus, when fault-prone regions are huge, it is cost eective
to use random testing technique.
4. Partition testing techniques identied 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 condence with the application.
For variety of scenarios, if the application functions properly, it gives a good condence 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 identied during
analysis are retained and are rened. 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 specication based testing technique. The specication used in
this thesis is not a complete specication for the development of the software, but for representing
the causal relation among various methods of the classes. The specication is the key for capturing
information about various classes and used extensively for testing. We have proposed two kinds of
specication. The Method Sequence Specication (MtSS) of a class documents the correct causal
order in which the methods of the class can be invoked. The Message Sequence Specication (MgSS)
of a method documents the causal order in which messages can be sent out to dierent 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 specication 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 specication 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 specication
can be captured. It is also possible to derive the sequence specication 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 specication is well-dened and most of
the derivation can be automated.
The importance of specication Consistency and Completeness (C&C) is well-known in software
engineering. Inconsistency and incompleteness in sequence specication would lead to faulty ver-
ication and therefore, C&C of the specication 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 identied 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 dierent 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 specication 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 verication system that checks for
the consistency of messages received at each object with respect to its sequence specication and
ags
out out-of-sequence messages. This kind of run-time verication is very essential in safety-critical
systems[53]. The run-time verication system maintains the sequence specication as a part of the
class structure. All the class instances keep track of the messages they receive and compare against
the sequence specication 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 verication
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 eectiveness, 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.
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 specication technique used in this thesis with the OO analysis and
design techniques so that all the V&V techniques that use sequence specication 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 specication 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 classication of dierent kinds of faults may not be
applicable in OO paradigm. Therefore the research issue is to identify and classify dierent 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 Articial 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 specications 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
Clis, 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 Articial 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
Pacic 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. Homan 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. Qualied 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. Specication and Verication 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. Retrotting 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 verication 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 Clis, NJ, 1991.
[67] S. Sankar and R. Hayes. ADL-an interface denition language for specifying and testing soft-
ware. In Proceedings of the Workshop on Interface Denition 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. Giord. 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 eectiveness 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 Clis, 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