A Taxonomy of OO Classes to Support the
Mapping of Testing Techniques to a Class
Peter J. Clarke, School of Computer Science,
Florida International University,
Miami
Brian A. Malloy, Department of Computer Science, Clemson
University, Clemson |
 |
REFEREED
ARTICLE

PDF Version |
Abstract
In this paper we describe a taxonomy of object-oriented classes that
catalogs each
class in an application according to the characteristics of that class,
including the
properties of the data attributes and routines as well as the relationships
with other
classes. Our taxonomy is motivated by the fact that the current research
literature
contains no formal methodology for capturing the characteristics of
a class. To illustrate
the advantages of the taxonomy, we apply it to the problem of choosing
implementation-based testing techniques and, more importantly, we show
that our
taxonomy can expose characteristics of a class that remain uncovered
by the chosen
testing technique.
1 INTRODUCTION
The trend in the development of large scale object-oriented systems
has shifted
toward testable, robust models, with a focus on the prevention of faults
and system
failure. One process that supports the construction of robust software
is testing.
An advantage of software testing is the relative ease with which some
of the testing
activities can be performed, such as executing the program using a
given set of
inputs, or test cases, and then comparing the generated output to the
expected
output [16]. However, the inadequacy of the infrastructure to support
testing is well
documented [30].
The widespread use of the object-oriented (OO) paradigm has lead
many developers
to treat the class or class cluster as the basic test unit in an
OO system [5].
However, the data attributes and routines of a class containing references,
pointers,
inheritance, polymorphism, restricted accessibility, and deferred
features complicate
class-based testing. These complications have resulted in an abundance
of classbased
testing techniques described in the literature [1, 6, 17, 18, 21,
23, 32, 33].
Each of the testing techniques addresses one or more of these complications
but no
one technique has emerged as the accepted approach de rigueur, possibly
because
no single technique addresses all of the complications that classes
may possess.
In this paper we describe a taxonomy of object-oriented classes that
catalogs
each class in an application according to the characteristics of
that class, including
the properties of the data attributes and routines as well as the
relationships withother classes. The class characteristics in our taxonomy
are captured by a set of
descriptors and a set of type families. Our taxonomy is motivated by
the fact that
the current research literature contains no formal methodology for
capturing the
characteristics of a class. Meyer describes an important taxonomy for
cataloging
inheritance usage groups [28, 29]. However, our taxonomy can be applied
to any
class and, using add-on descriptors, is adaptable to a wide range of
OO languages.
Using the descriptors and type families, we show that our taxonomy
partitions the
set of C++ classes into mutually exclusive sets.
To illustrate the advantages of the taxonomy, we apply it to the
problem of
choosing implementation-based testing techniques and, more importantly,
we show
that our taxonomy can expose characteristics of a class that remain
uncovered by
the chosen testing technique. We describe a mapping algorithm that
automates
the process of matching a class under test (CUT) to a list of implementation-based
testing techniques (IBTTs), reducing the analysis time required by
the tester. The
matching process identifies those IBTTs that can suitably test characteristics
of the
CUT and provides feedback to the tester for identification of the characteristics
of
the CUT that are not suitably tested by any of the IBTTs in the list.
The taxonomy
has also been applied to the non-trivial problem of computing impact
analysis as a maintenance activity [12].
In the next section we provide background and terminology about classes,
classbased
testing and class abstraction techniques. In Section 3 we provide
motivation for our taxonomy of OO classes. In Section 4 we describe
our taxonomy
and in
Section 5 describe our approach to mapping IBTTs to classes to suitably
test a
CUT. We review the related work in Section 6 and draw conclusions
in Section 7.
2 BACKGROUND
In this section we introduce the terms class characteristics,
implementation-based testing, class abstraction and taxonomy. We also present a brief
overview of several
IBTTs that we use to provide motivation for our taxonomy of OO
classes.
Class Characteristics
Meyer defines a class as a static entity that represents an abstract
data type with a
partial or total implementation [29]. The static description
supplied by a class should
include a specification of the features that each object
might contain. These features
fall into two categories: (1) attributes, and (2) routines.
Attributes are referred to as
data items and instance variables in other OO languages while
routines are referred
to as member functions and methods. Throughout this paper
we use the terms
attributes and routines.
We define the class characteristics for a given class C as
the properties of the features
in C and the dependencies C has with other types
(built-in and user-defined)in the implementation. The properties of
the features in C describe how criteria
such as types, accessibility, shared class features, polymorphism,
dynamic binding,
deferred features, exception handling, and concurrency
are represented in the attributes
and routines of C. The dependencies of C with other types
are realized
through declarations and definitions of C’s features
and C’s role in an inheritance
hierarchy.
The properties of the features in a class have been reviewed
in the literature
[2, 26, 29, 34]. Most of the terms we use in this paper
about the properties of the
features in a class are keywords in the programming languages
C++ [34], Eiffel [29],
or Java [2]. The dependencies among classes are usually
the result of declarations
or definitions of features, or the participation in an
inheritance hierarchy. The
attributes and routine locals (variables or parameters)
of a class can be declared as
one of many possible types. These types include: built-in
types, user defined types,
and types provided by specialized libraries. Some OO languages
also allow the use
of parameterized types whereby the actual type of the attribute
or routine local is
only known when an instance of the class is created. Inheritance allows features
of the class to be reused in another class and permits
the class to be extended to
include new features [29]. The use of inheritance may result
in some classes having
deferred features.
Class Abstraction Techniques
There are several class abstraction techniques (CATs) that
provide alternative views
of an implemented class (or a cluster of classes) by reverse
engineering the source
code [8, 14]. The CATs we consider in this paper are referred
to by Gannod et al. [14]
as parser-based because they are based on the syntactic
properties of a programming
language. We focus on CATs that support testing during
the software development
process. These parser-based CATs typically fall into four
broad categories: (1) use
of graphs for design recovery [22, 24, 27], (2) use of
graphs for program analysis
[6, 18, 32, 33], (3) extraction of object oriented design
metrics (OODMs) [7, 15, 25],
and (4) classification of class characteristics [17, 28].
Design information recovered from the source code of a
software implementation
assist the tester in identifying the relationships that
exists between the different
entities in the source code. Knowledge of these relationships
can reduce the cost of
testing by generating a test order to reduce the number
of stubs and/or drivers [5].
Program analysis is used to generate test information for
several testing techniques.
Many of the graphs used during the generation of test information
are derived from
control flow graphs (CFG), described in the next subsection.
There is a greater
semantic difference between the source code and the graphs
used during design
recovery than between the source code and the graphs generated
for program analysis
[14].
Design metrics are used to determine or measure the quality
of a software application.
Basili et al. [4] show that several of Chidamber and Kemerer’s
[7] OODMs appear to be useful in predicting class fault-proneness
during the early phases of the
software development. Harrold et al. [17] classify the
features that a descendant
class in the C++ language may have. These include new
feature, recursive feature,
redefined feature, virtual-new feature, virtual-recursive
feature and virtual-redefined feature. New features are declared in the descendant class
and recursive features are
inherited from the parent class unchanged. A redefined
feature is a routine that has
the same signature as a routine declared in the parent
but with a different implementation.
A virtual feature refers to a routine that is dynamically
bound. Meyer
[28] presents a taxonomy that classifies the various inheritance
usage groups.
In this paper we use the following definition of the term
taxonomy [35]:
A taxonomy is the science of classification according
to a pre-determined
system, with the resulting catalog used to provide
a conceptual framework
for discussion, analysis, or information retrieval.
In theory, the
development of a good taxonomy takes into account the
importance of
separating elements of a group (taxon) into subgroups
(taxa) that are
mutually exclusive, unambiguous, and taken together,
include all possibilities.
Implementation-Based Testing
We define implementation-based testing of an OO class
as the process of operating a
class under specified conditions, observing or recording
the results, and making an
evaluation of the class based on aspects of its implementation
(source code). This
definition is based on the IEEE/ANSI definition for
software testing [19]. This paper
focuses on testing techniques that generate test information
based on the implementation,
we refer to these techniques as Implementation-Based
Testing Techniques or
IBTTs. We now provide a brief overview of a cross-section
of IBTTs described in
the literature.
Test Tuple Generation: Several
IBTTs generate test cases from tuples (referred
to as test tuples) based on some type of coverage
criteria. Harrold and Rothermel
present a data flow testing technique for classes
based on the procedural programming
paradigm [18]. The technique described in [18] uses
the class control flow
graph (CCFG) to represent the classes in a program.
Data-flow information computed
from the CCFG is used to generate intra-method, inter-method and intra-class def-use
pairs [18]. Sinha and Harrold describe a class of adequacy
criteria that is
used to test the behavior of exception-handling constructs
in Java programs [32].
The approach described in [32] is similar to that
presented in [18], that is, data-flow
analysis is performed on an inter-procedural control
flow graph (ICFG) that incorporates
exception-handling constructs resulting in the identification
of test tuples.
Souter and Pollock propose a testing technique known
as OMEN (Object Manipulations
in addition to using Escape Information) that uses
data-flow analysis based
on object manipulations to generate test tuples [33].
OMEN is based on a compiler optimization strategy
for Java programs that creates a points-to-escape graph
for a
given region of the program.
Koppol et al. describe a testing technique that generates
test sequences selected
from labeled transition systems (LTS) [21]. An
LTS is a type of state machine used
to model programs. The common approach to selecting
test sequences from a reachability
graph. To overcome the state explosion problem
with traditional reachability
graphs, Koppol et al. defined a new type of reachability
graph for incremental analysis
called an annotated labeled transition system (ALTS)
[21]. During incremental
analysis test paths can be selected from the intermediate
graphs or from the final reduced
graph. Alexander and Offutt, present OO coupling
criteria that focus on the
effects of inheritance and polymorphism [1]. This
criteria uses quasi-interprocedural
data flow analysis, that is, complete information
about data flows between units are
not needed. This approach requires data flow information
from definitions to call
sites, from call sites to uses, and from entry
definitions to exit nodes [1].
Message Sequence
Generation: Some IBTTs generate message sequences that
are executed by instances of the CUT. These message
sequences are generated based
on criteria associated with the implementation
of the CUT. Buy et al. propose
an automated testing strategy for classes that
uses data-flow analysis, symbolic
execution, and automatic deduction [6]. This
IBTT generates message sequences
seeking to reveal failures dependent on the
current state of the object. Kung et
al. use symbolic execution to generate an object
state test model that is used to
construct a test tree [23]. The method sequences
are then generated from the test
tree. The object state test model is represented
as a hierarchical, concurrent object state
diagram (OSD), which identifies the possible
states an object can enter during
execution. A test tree is generated from the
OSD and message sequences produced.
Test Case Reuse: Harrold et al. propose a testing
technique that uses an incremental
approach to testing OO software dependent on
the inheritance hierarchy
component of the class structure [17]. The
incremental approach reuses test sets created
for the class at the root of the inheritance
hierarchy based on derived features. These
derived features are classified as: new and
recursive for both attributes and
routines; redefined, virtual-new, virtual-recursive,
and virtual-redefined for routines
only [17].
3 MOTIVATION FOR A TAXONOMY OF OO CLASSES
Our taxonomy of OO classes is motivated by
the fact that there is no formal methodology
described in the literature for capturing
the characteristics of a class. However,
a formal and succinct method for describing
a class would benefit both researchers
and practitioners in the area of OO testing.
These benefits include: (1) further
automating the testing process by mapping
IBTTs to a class under test (CUT), (2)
using the information generated from the
class cataloging process to support the
execution of IBTTs, and (3) providing a
basis for analyzing the type of coverage
currently provided by existing IBTTs.

Table 1: Summary of IBTTs identifying the class characteristics
that are suited to and not suited to the respective IBTT. The characteristics in Columns
2 and 3, and
the scope in Column 4 are extracted from references cited in Column
1.
Table 1 shows a summary of the class characteristics that can be suitably
tested by a given IBTT and those class characteristics
that cannot be suitably
tested by
that IBTT. The term suitably tested is used to identify those
characteristics of a
CUT that can be adequately tested by an IBTT in the opinion of the
researcher
(or tester). Column 1 identifies the main researcher that developed
the IBTT and
the name we associate with that IBTT, shown in italics. Column 2 identifies
those
class characteristics that can be suitably tested by the IBTT
in Column 1 of that
row. Column 3 identifies those class characteristics that cannot be
suitably tested by the IBTT in Column 1 of that row.
Column 4 identifies the scope for which
the IBTT in Column 1 can be used to suitably test the characteristics
in Column 2.
Note that the class characteristics in Columns 2 and 3, and
scope in Column 4 were
extracted from the respective references shown in Column 1. For example,
Row 2 of Table 1 represents the information for the IBTT developed by
Buy et al.[6]. The
name assigned to the IBTT developed by Buy et al. is Automated, shown
in Row 2
Column 1. The class characteristics that can be suitably tested by the
Automated
IBTT include: primitive types, and simple control flow, shown in Row
2 Column
2. The class characteristics that cannot be suitably tested by the Automated
IBTT
include: complex variables - arrays, structs; references to variables,
shown in Row 1
Column 3. For a further explanation on the meaning of the class characteristics
for
each IBTT see the respective references listed in Column 1.
The information in Table 1 indicates that some IBTTs are more suitable
for testing classes that exhibit certain characteristics. Automating the process
to generate
the summary of class characteristics for the CUT and mapping IBTTs
to the CUT,
reduces the time the tester must spend analyzing the source code of
the CUT and
its dependencies. Cataloging classes in a program using the appropriate
classification
can also support the execution of existing IBTTs. For example, the
IBTT by
Harrold et al. [17] (Incremental), Row 3 of Table 1, identifies those
test cases that
can be reused from the test history of a parent class to test a derived
class. To
achieve the aforementioned goal the cataloging process should include
the classification of the features in a derived class, as stated in
Section 2 - Test Case Reuse.
The final advantage of cataloging the classes in a program, using the
appropriate
classification, is that it provides a way of identifying how much coverage
is provided
by existing IBTTs with respect to class characteristics. That is, how
many different
groups of classes currently exist, and how many of these groups can
be suitably tested by existing IBTTs.
4 TAXONOMY OF OO CLASSES
In this section we describe our Taxonomy of OO Classes that is used
to catalog each
class in an OO software application based on the characteristics of
that class. These
characteristics include the properties of the class’ features
(attributes and routines)
and the dependencies with other classes in the software application.
Structure of the Taxonomy
Our taxonomy of OO classes provides a mechanism whereby classes
in any OO
language may be cataloged producing a cataloged entry. This cataloged
entry contain
components representing the characteristics of class in a formal yet
succinct manner.
Following we define the terms associated with our taxonomy of OO classes
[9].
Definition 4.1: Taxonomy of OO Classes. A taxonomy
of OO classes T,
classifies an OO class C into a group based on the dependencies C has with other
types (built-in and user-defined) in the software application. The
dependencies of
C with other types are realized through declarations and definitions
of C’s features
and C’s role in an inheritance hierarchy. A class is
cataloged using the taxonomy of OO classes T to produce a a summary
of class characteristics. This summary of class characteristics is
referred to as a
cataloged entry.
Definition 4.2: Cataloged Entry. Each cataloged
entry generated
using T is a
5-tuple (C, N, A, R, F), where:
- C is the fully qualified name
of the class.
- N, the Nomenclature Component, represents
a group (or taxon) in T and contains a single entry.
- A, the Attributes Component, is a list
of entries representing the different
categories of attributes.
- R, the Routines Component, is a list
of entries representing the different categories
of routines.
- F, the Feature Classification Component,
is a list of entries summarizing the
inherited features.
The Attributes, Routines and Feature Classification Components
are collectively
referred to as Feature Properties. The entries in the Nomenclature
Component, Attributes
Component and Routines Component are referred to as component
entries.
Following is the definition of a component entry:
Definition 4.3: Component Entry. A component
entry in the Nomenclature,
Attributes, or Routines Components for class C cataloged using
taxonomy T consists
of two parts: (1) the modifier that describes characteristics
of C, and (2) a list of
type families that identifies the types associated with C.
One of the major goals of the taxonomy is the ability to represent
the characteristics
of a class written in virtually any OO language. To achieve
this goal the
modifier part of a component entry is divided into two parts:
(1) core descriptors that represent common characteristics found in OO languages,
and (2) add-on descriptors that represent characteristics peculiar to a specific OO language.
Table
2 shows the descriptors and type families used to generate
the various component
entries in a cataloged entry. Column 1 in Table 2 shows the
descriptors used in the
modifier part of the Nomenclature Component entry. Columns
2 and 3 show the
descriptors used in the modifier part for each entry in the
Attributes and Routines
Components respectively. The descriptors in parentheses represent
the add-on descriptors
used to describe the characteristics of a class peculiar to
the C++ language.
Column 4 shows the types families used in the Nomenclature,
Attributes and Routines
Component entries. The descriptors and types families in Table
2 are formally
described in reference [9], an informal description is presented
in reference [12]
Illustrative Example
Figure 1 illustrates an application of our taxonomy to a C++
class. Figure 1(a)
shows the C++ code for classes Point, Cartesian and Polar.
Class Point declares
two protected attributes, x and y, both of type int and
five public routines three constructors, a virtual destructor,
and the constant virtual routine print. Classes
Cartesian and Polar inherit from Point.
Table 2: Descriptors (core and add-on) and type families
used in a cataloged entry.
The descriptors in parentheses are the add-on descriptors used to
describe the
characteristics peculiar to the C++ language.
Figure 1(b) illustrates the cataloged entry for class Point.
The Nomenclature
Component entry for class Point is Parent Families P, U* for the
following reasons:
Point is the root of an inheritance hierarchy (Parent), and the
data types used in
declarations are the primitive type int (Family P)and a reference
to the user-defined
type Point (Family U*). The entry in the Attributes Component,
is [2] Protected
Family P that represents the attributes x and y, line 3 Figure
1(a).
The entries in the Routines Component for the constructors
are: [1] Non-Virtual
Public Family NA representing the zero argument constructor Point(),
line 5, [1] Non-Virtual Public Family P representing the two argument constructor
Point(int
inX, int inY), line 6, and [1] Has-Polymorphic Non-Virtual
Public Family U* for
the one argument constructor Point(Point & p), line 8. The
destructor ~Point() is
cataloged as Virtual Public Family NA and routine print() as (Constant)
Virtual
Public Family NA. The descriptors Protected and Public reflect
the accessibility for
the attributes and routines in class Point. The binding of the
routines are represented
by the descriptors Non-Virtual - static and Virtual - dynamic.
The add-on descriptor
Constant, peculiar to C++, states that the routine print() prevents
attributes of the
class from being modified. The Feature Classification Component
in the cataloged
entry for class Point contains the entry None because class Point
is not a derived
class, thereby not containing any derived features.
Figure 1: (a) C++ code for classes Point, Cartesian, and Polar.
(b) Cataloged entry
for class Point.
Properties of the Taxonomy
The properties of our taxonomy of OO classes are: (1) all groups
of OO classes
are mutually exclusive, (2) each component entry is specified
in an unambiguous
manner, and (3) all classes written in virtually any OO language
can be cataloged
into a group. In this subsection we describe how our taxonomy
of OO classes
satisfies properties (1) and (3). For property (2) we developed
a regular grammar
that generates all possible strings for the components entries
in a cataloged entry
[9].
Figure 2 shows a tree illustrating how our taxonomy of OO classes
partitions the
set of classes into mutually exclusive groups (or taxa).
Figure 2 contains only the
core descriptors and type families. An example of one such
group is Non-Generic
Sequential Concrete Inheritance-Free Families P, shown along
the top branch of the
tree in Figure 2. Since we consider the descriptors Non-Generic,
Sequential, and
Concrete, as default descriptors, the Nomenclature
becomes
Inheritance-Free Families
P. This group represents classes that are not part of an
inheritance hierarchy
and contain data (attributes and routine locals) whose types
are primitive. The
default descriptors, shown in italics in Figure 2, are added
to ensure that the groups
of the taxonomy are mutually exclusive. A similar tree can
also be created for the
add-on descriptors and preprended to the tree in Figure 2.
Our results show that the
taxonomy generates 305664 groups of C++ classes [9]. In reference
[9] we formally
define the descriptors using predicates and functions. In
addition, all the possible type families are define using
set theory notation.

Figure 2: Mutually exclusive groups of classes.
This figure illustrates the mutually
exclusive groups, taxa, of classes that are cataloged by our
taxonomy. One such
group, Non-Generic Sequential Concrete Inheritance-Free Families
P, is illustrated
in the upper right corner of the figure.
The approach used to show that the taxonomy covers all possible classes written
in the C++ language is based on the fact that a class definition uses one or more
keywords. Starting with the C++ keywords, we identify all those keywords used
in class definitions that are related to a class characteristic and hence a descriptor
(core and add-on) used in a component entry of the taxonomy. For each of the
keywords related to a descriptor, the context in which the keyword is used in a class
definition is stated and the associated descriptor identified. The grammar for the
C++ language [20] is used to identify the context in which each related keyword
is used. For example, the keyword class is used in six different contexts in a class
definition. These contexts of the keyword class maps to the descriptors Inheritancefree,
Parent, External Child, Internal Child, (Nested), and (Multi-Parent). A similar
approach is used for the type families used in the component entries of the taxonomy.
5 MAPPING OF TESTING TECHNIQUES TO A CUT
In this section we describe the process used to map IBTTs to
a CUT. The mapping process takes as input a summary of the CUT
and a list summarizing the IBTTs
available to the tester, then identifies those IBTTs that can suitably
test features of the CUT. We assume that the list summarizing the
IBTTs is initialized by the
tester based on his/her experience and the current testing environment, i.e.,
the availability of IBTTs.
Mapping Process
The mapping process accepts a summary of the CUT and a list
summarizing the
IBTTs available to the tester, then identifies those features
of the CUT that can
(cannot) be suitably tested by an IBTT. In Section 3 we stated
that the term suitably
tested is used to refer to those entities that are adequately
tested in the opinion of
the researcher or the tester.
The CUT is cataloged using our taxonomy of OO classes to produce
a cataloged
entry similar to the one shown in Figure 1(b). A similar
approach is used to
summarize the IBTTs available to the tester. That is, for
each IBTT one or more
catalog entries are created by the tester associating the
characteristics of the class
that can be suitably tested by that IBTT. Each IBTT cataloged
entry contains the
fields: (1) Priority - identifies the priority assigned by
the tester, (2) Nomenclature - group of classes suitably
tested by the IBTT, (3) Attributes - groups of attributes
suitably tested, and (4) Routines - groups of routines suitably
tested. The entries
in the Nomenclature, Attributes and Routines Components are
represented using
EBNF notation. The tester assigned priority is used to order
IBTTs that can be
used to test the same groups of attributes or routines.
In order to match the component entries in the catalog entry
for the CUT and
a cataloged entry for an IBTT we use the matches operator
defined as follows:
Definition 5.1: Boolean operator matches ( ).
The value of a component
entry A matches a component entry B if and only if: (1)
the string of descriptors in
the modifier part of A is a string in the language generated
by the modifier part of
B, and (2) the intersection of type families in A and
B is nonempty. That is,
where C.modifier is the string of descriptors of C,
L(C.modifier) is the language
generated by the modifier component of C, and C.typeFamily is the set containing
the type families of C.
An example of the matches operator is, New Non-Virtual
Public Families P U New (Non-Virtual | Virtual) (Private | Protected | Protected) [Static]
Family P,
that evaluates to true. Using Definition 5.1 the component
entries in the example
match, because New Non-Virtual Public L(New (Non-Virtual
| Virtual) (Private | Protected | Public) [Static] ) and 
Mapping Algorithm
The algorithm IBTT CUTMap shown in Figure 3 maps
IBTTs to a CUT. The
mapping relation from IBTTs to a CUT is suitably
test. The parameters passed to
algorithm IBTT CUTMap, Figure 3, consist of:
(1) cutEntry - a cataloged entry for
the CUT and (2) ibttList - a list containing
a summary of the IBTTs available to the
tester. Note that the tester is responsible for
initializing ibttList. The data returned
from algorithm IBTT CUTMap is stored in the variable
ibttCutMap. The data in ibttCutMap consists of: (1) tupleList
- a list of tuples representing the mapping from
IBTTs to the CUT, and (2) harsNotTestedList - a list of the
class characteristics
that cannot be suitably tested by any IBTTs in ibttList.
 Figure 3: Overview of Algorithm to map IBTTs
to a CUT.
Line 3 of algorithm IBTT CUTMap shown in Figure 3 initializes
the fields in ibtt-CutMap. Line 4 creates ordered pairs for
all the entries in the Attributes and Routines
Components of cutEntry and adds them to the variable ibttCutMap.charsNot-TestedList.
The loop lines 5 through 23 sequences through each IBTT in ibttList.
The entries in the various components of the IBTT under consideration
are compared
to the entries in the corresponding components in the CUT seeking
a match.
If there is a match between the corresponding Nomenclature
component entries, line
8, then the Attributes and Routines component entries are compared.
A match between
corresponding entries in the Attributes Component, line 11,
creates a 4-tuple,
adds it to the tuple list ibbtCutMap.tupleList, and the component
entry of the CUT,
cutEntry.Attr, in ibttCutMap.charsNotTestedList is tagged as
tested. If more than one
feature can be suitably tested by an IBTT then ibbtCutMap.tupleList
contains the IBTT with the highest priority.
Similar actions, to those for the Attributes Component, are
performed for the
entries in the Routines Component, line 17. The only change
is that the difference
between the type families of the component entries being
matched may not be the
empty set, line 17. To use the priority field in deciding
which IBTT to use to test
the routine the difference between the type families of the
component entries on line
17 must be the same. When the 4-tuple, line 18, is created
it is pdated with the
type families that matched on line 17 and the appropriate
descriptors.
The running time of algorithm IBTT CUTMap is . The value j represents the number of IBTTs in the input list ibttList
and n is the cost required
to check if Nomenclature component entries match, line
8 of Figure 3. The value a is the cost to compare each entry in the Attributes Component
of the CUT and the
IBTT entry line 11. The value r is the cost to compare
each entry in the Routines
Component of the CUT and the IBTT entry, line 17 of Figure
3. Note that although
the running time appears to be a cubic function, the values
of a and r are expected
to be small [11]. An Application of the Mapping Algorithm
In this subsection we describe an application of algorithm
IBTT CUTMap shown in
Figure 3. The input to algorithm IBTT CUTMap consist of:
(1) a cataloged entry
for class Point, Figure 1(b), and (2) a summary of the
Data-Flow IBTT by Harrold
et al. [18], Figure 4. In this example the Data-Flow IBTT
is assigned the unique
identifier Data-Flow Harrold94. We limit the number of
IBTTs in this example to
one due to the space restrictions. We stress the fact that
the summary of IBTTs in
ibttList, the second input parameter of algorithm IBTT
CUTMap, is supplied by the
tester. For the purpose of this example we assigned possible
values to the component
entries of the Data-Flow IBTT in Figure 4.
The component entries of each cataloged entry in Figure
4 is written using EBNF
notation. For example, the Nomenclature component entry
in the first cataloged
entry of the IBTT summary for Data-Flow Harrold94 is (Inheritance-free | Parent) Family
P. This Nomenclature entry says that this IBTT can
be used to suitably
test: (1) any class that is not part of an inheritance
hierarchy and contains primitive
data types, or (2) any class that is the root of an inheritance
hierarchy and
contains primitive data types. The Attributes entry for
the first cataloged entry in
Data-Flow Harrold94, Figure 4, is (Private | Protected)
[Static] Family P. The entry
states that Data-Flow Harrold94 can suitably test attributes
that are either private
or protected, can be static, and are primitive types.
The output generated after applying algorithm IBTT CUTMap
to cutEntry, containing
a cataloged entry of class Point, and ibttList, containing
catalog entries for
Data-Flow Harrold94, is shown in Figure 5. Figure 5(a)
represents the variable ibbt-CutMap a local variable
that references the two lists returned from IBTT CUTMap.

Figure 4: Summary of the Data-flow IBTT, the
single IBTT stored in ibttList, used
as input to algorithm IBTT CUTMap.
These lists include: (1) ibbtCutMap.tupleList - the features
of class Point suitably
test by Data-Flow Harrold94, Figure 5(b), and (2) ibttCutMap.charsNotTestedList
-
the features that cannot be suitably tested by Data-Flow Harrold94,
Figure 5(c). The
first entry in Figure 5(b) is a 4-tuple consisting of: (1) Characteristic
- a component
entry representing the attributes x and y in class Point, (2)
Feature Pairs - consisting
of (x, ATTRIBUTE) and (y, ATTRIBUTE) for the two attributes in
class Point, (3)
IBTT Name - the IBTT Data-Flow Harrold94, that can suitably test
the listed feature
pairs, and (4) IBTT Priority - tester assigned priority, 3. Figure
5(c) contains a
list of 2-tuples, each 2-tuple consisting of the feature characteristics
that cannot be
suitably tested by any IBTT, and a list of the features with
the stated characteristic.
Applying algorithm IBTT CUTMap, Figure 3, to the input described
in paragraph
one of this subsection results in the following events. The
variable ibbtCutMap
is initialized on line 3 of algorithm IBTT CUTMap. All the
Attributes and Routines
component entries from the CUT for class Point are copied to
the variable ibbt-
CutMap.charsNotTestedList, line 4. There is only one ibtt in
ibttList therefore the
loop lines 5 through 23 is executed once. A match occurs on
line 8 between the
Nomenclature component entry of cutEntry and the first cataloged
entry for the
IBTT Data-Flow Harrold94, Figure 1(b) and Figure 4 respectively.
A match occurs
between the Attribute component entries, line 11 of algorithm
IBTT CUTMap, resulting
in a 4-tuple being created and added to ibbtCutMap.tupleList,
the first entry in Figure 5(b). In addition, the component entry
Protected Family P is tagged for deletion
in ibbtCutMap.charsNotTestedList. The second entry in ibbtCutMap.tupleList,
Figure 5(b), is added as a result of a match between the Routine
component entry
for the two-argument constructor Point and the Routine component
entry in the first
cataloged entry for the IBTT Data-Flow Harrold94. There is no
match between the
Nomenclature entries of the CUT and the second cataloged entry
of the IBTT Data-
Flow Harrold94, line 5 of algorithm IBTT CUTMap, resulting in
variable ibbtCutMap,
Figure 5, being returned.

Figure 5: Output of algorithm IBTT CUTMap after
mapping the IBTT Data-Flow Harrold94 to class Point. (a) Structure
of variable ibttCutMap. (b) Contents
of list ibttCutMap.tupleList. (c) Contents of list ibttCutMap.charsNotTestedList.
Limitations of the Mapping Process
There are several limitations of our mapping process. One limitation
is the fact
that our taxonomy does not capture any information regarding
the type of control
structures used in the various routines in a class. Several
pre-OO IBTTs used
coverage criteria based on the analysis of control structures
[31]. A second limitation
is that algorithm IBTT CUTMap does not fully exploit the priorities
assigned to the
IBTT, in particular the priorities assigned to individual catalog
entries for an IBTT.
We are investigating ways to fully utilize these priorities
to provide better accuracy
in the mapping process.
6 RELATED WORK
The class abstraction techniques (CATs) used during testing
include graphs for
design recovery, graphs for program analysis, OODMs and the
classification of class
characteristics. In this section we focus on CATs that are
closely related to the
classification of class characteristics.
Harrison et al. [15] overview three OODM sets, including
a cross-section of the
set developed by Lorenz et al. [25]. The OODM set by Lorenz
et al. contains
metrics that reflect certain characteristics of a class closely
related to our taxonomy
of OO classes. Three of the metrics in the set by Lorenz et
al. are: Number of Public
Methods (PM), Number of Methods Inherited by a subclass (NMO),
and Number of
Methods Overridden by a subclass (NMO). Although the OODM set
by Lorenz et
al. identify several class characteristics it does not show
how these characteristics
are combined in the class. Our taxonomy of OO classes can identify
the number of
routines (methods) in a derived class that are public and inherited
(recursive). The
combination of class characteristics are essential when mapping
IBTTs to a CUT.
An analysis of our cataloged entry reveals that of the 10 OODMs
by Lorenz et al.
[25], reviewed by Harrison et al. [15], TaxTOOL generates 8
of them directly [9].
Harrold et al. [17] classify the features of a derived
class and use this classification to identify those test
cases from the parent’s
test history that can be reused
when testing the derived class. A brief summary of the testing
technique by Harrold
et al. is presented in Section 2. Our taxonomy of OO classes
extends the classification
presented by Harrold et al. [17] to include characteristics
for all classes
written in virtually any OO language. In addition to the classification
of inherited
features we classify properties of features such as types,
accessibility, shared class
features, polymorphism, dynamic binding, deferred features,
exception handling,
and concurrency. The dependencies of a class with other types
are also classified in
our taxonomy. Barbey et al. [3] state that the approach by
Harrold et al. can be
enhanced by first cataloging the inherited class using the
taxonomy of inheritance
usage groups proposed by Meyer [28, 29]. Unlike our approach
to cataloging classes
which is based solely on the syntactic structure of the source
code, English et al. [13]
concluded that semantic analysis is necessary in almost 70%
of the cases categorized
into the individual inheritance relationships identified by
Meyer.
An initial version of our taxonomy of OO classes is presented
in reference [10].
The version presented in this paper has been revised as follows:
(1) extending the
number of descriptors in the Nomenclature, Attributes, and
Routines components
to more accurately summarize the characteristics of the class,
(2) using add-on
descriptors to catalog classes written in virtually any OO
language, (3) renaming
the type families (class associated types) to be more meaningful,
and (4) extending
the type families to include parameterized types. The mapping
process in reference
[10] is based solely on the Nomenclature component entry.
We have extended the
mapping process to include the entries in the Attributes
and Routines components.
In addition, we have defined the Boolean operator matches that
uses both parts of a component entry to identify if an IBTT
can suitably test a feature in the CUT.
7 CONCLUDING REMARKS
We have presented a taxonomy of object-oriented classes that
catalogs each class in
an application according to the characteristics of that class,
including the properties
of the data attributes and routines as well as the relationships
with other classes.
The class characteristics in our taxonomy are captured by
a set of descriptors and
a set of type families. We have described our use of add-on
descriptors to enable
the taxonomy to be applied to a wide range of OO languages.
Using the descriptors
and type families, we show that our taxonomy partitions the
set of C++ classes
into mutually exclusive sets. We described a mapping algorithm
that uses the taxonomy
to automate the process of matching a class under test (CUT)
to a list of
implementation-based testing techniques (IBTTs), reducing
the analysis time required
by the tester. The matching process identifies those IBTTs
that can suitably
test characteristics of the CUT and provides feedback to
the tester for identification
of the characteristics of the CUT that are not suitably
tested by any of the
IBTTs in the list. Our taxonomy has also been applied to
the non-trivial problem
of computing impact analysis as a maintenance activity [12].
REFERENCES
[1] R. T. Alexander and A. J. Offutt. Criteria for testing
polymorphic relationships.
In Proceedings of the 11th International Symposium on
Software Reliability Engineering,
pages 15–24. ACM, Oct. 2000.
[2] K. Arnold, J. Gosling, and D. Holmes. The Java
Programming Language. Addison
Wesley, Reading, Massachusetts, third edition, 2000.
[3] S. Barbey and A. Strohmeier. The problematics of
testing object-oriented software.
In Proceedings of SQM’94 Second Conference on Software
Quality Management,
pages 411–426. Comp. Mech. Publications, July 1994.
[4] V. R. Basili, L. C. Briand, and W. L. Melo. A validation
of object-oriented design
metrics as quality indicators. IEEE Transactions on Software
Engineering,
22(10):751–761, October 1996.
[5] R. V. Binder. ”Testing Object-Oriented
Systems: Models, Patterns, and Tools”.
Addison-Wesley, Reading, Massachusetts, 2000.
[6] U. Buy, A. Orso, and M. Pezze. Automated testing
of classes. In Proceedings
of ISSTA, pages 39–48, August 2000.
[7] S. R. Chidamber and C. F. Kemerer. A metrics suite
for object oriented design.
IEEE Transactions on Software Engineering, 20(6):476–493,
June 1994.
[8] E. J. Chikofsky and J. H. Cross. Reverse engineering
and design recovery: A
taxonomy. IEEE Software, 7(1):13–17, January 1990.
[9] P. J. Clarke. A Taxonomy of Classes to Support
Integration Testing and the
Mapping of Implementation-based Testing Techniques to Classes.
PhD thesis,
Clemson University, August 2003.
[10] P. J. Clarke and B. A. Malloy. Identifying implementation-based
testing techniques
for classes. International Journal of Computers and Information
Systems,
3(3):195–204, September 2002.
[11] P. J. Clarke and B. A. Malloy. Using a taxonomy to
analyze classes during
implementation-based testing. In The 8th IASTED International
Conference
on Software Engineering and Applications, pages 288–293.
IASTED, Nov 2004.
[12] P. J. Clarke, B. A. Malloy, and P. Gibson. Using a
taxonomy tool to identify
changes in OO software. In 7th European Conference on
Software Maintenance
and Reengineering, pages 213–222. IEEE, March 2003.
[13] M. English, J. Buckley, and T. Cahill. Applying meyer’s
taxonomy to objectoriented
software systems. In Third International Workshop on
Source Code
Analysis and Manipulation, pages 35–34. IEEE, September
2003.
[14] G. C. Gannod and B. H. C. Cheng. A framework for classifying
and comparing
software reverse engineering and design recovery tools. In
Proceedings of the
6th Working Conference on Reverse Engineering, pages 77–78,
October 1999.
[15] R. Harrison, S. Counsell, and R. Nithi. An overview
of object-oriented design
metrics. In 8th International Workshop on Software Technology
and Engineering
Practice, pages 230–237. IEEE, July 1997.
[16] M. J. Harrold. Testing: A roadmap. In Proceedings
of the Conference on The
Future of Software Engineering, pages 61–72, New York,
Dec. 2000. ACM.
[17] M. J. Harrold, J. D. McGregor, and K. J. Fitzpatrick.
Incremental testing of
object-oriented class structures. In ICSE, pages 68–80,
May 1992.
[18] M. J. Harrold and G. Rothermel. Peforming data flow
testing on classes. In
Proceedings of FSE, pages 154–163, December 1994.
[19] IEEE/ANSI Standards Committee. Std 610.12-1990. 1990.
[20] ISO/IEC JTC 1. International Standard: Programming
Languages - C++. Number 14882:1998(E) in ASC X3. ANSI, first
edition, September 1998.
[21] P. V. Koppol, R. H. Carver, and K. C. Tai. Incremental
integration testing of
concurrent programs. IEEE Transactions on Software Engineering,
28(6):607– 623, June 2002.
[22] C. H. Kung, J. Gao, P. Hsia, J. Lin, and Y. Toyoshima.
Design recovery for
software testing of object-oriented programs. In Proceedings
WCRE, pages
202–211, May 1993.
[23] D. Kung, Y. Lu, N. Venugopalan, P. Hsia, Y. Toyoshima,
C. Chen, and J. Gao.
Object state testing and fault analysis for reliable software
systems. In Proceedings
of ISSRE, pages 239–244, August 1996.
[24] Y. Labiche, P. Thevenod-Fosse, H. Waeselynck, and
M. H. Durand. Testing
levels for object-oriented software. In Proceedings of
ICSE,
pages 136 – 145,
New York, June 2000.
[25] M. Lorenz and J. Kidd. Object-Oriented Software
Metrics.
Printice Hall Object-Oriented Series, 1994.
[26] K. C. Louden. Programming Languages Principles
and Practice. PWS Publishing
Company, 1993.
[27] B. A. Malloy, P. J. Clarke, and E. L. Lloyd. A parameterized
cost model to
order classes for integration testing of C++ applications.
In Proceedings of
the 14th International Symposium on Reliability Engineering
(ISSRE ’03), Los
Alamitos, CA, Nov. 2003. IEEE Computer Society Press.
[28] B. Meyer. The many faces of inheritance: a taxonomy
of taxonomy. IEEE
Computer, 29(5):105–108, May 1996.
[29] B. Meyer. Object-Oriented Software Construction. Prentice
Hall PTR, 1997.
[30] NIST. The economic impacts of inadequate infrastructure
for software testing.
Technical Report, May 2002.
[31] M. Roper. Software Testing. McGraw-Hill, 1994.
[32] S. Sinha and M. J. Harrold. Analysis and testing of
programs with exception
handling constructs. IEEE Transactions on Software Engineering,
26(9):849– 871, September 2000.
[33] A. L. Souter and L. L. Pollock. OMEN: A strategy for
testing object-oriented
software. In Proceedings of the International Symposium
on Software Testing
and Analysis, pages 49–59. ACM, August 2000.
[34] B. Stroustrup. The C++ Programming Language (Special
3rd Edition).
Addison-Wesley, 2000.
[35] Whatis. Whatis.com target searchTM . http://whatis.techtarget.com/,
May 2002.
About the authors
Peter J. Clarke is an Assistant Professor in the School of Computer
Science
at Florida International University. He received his Ph.D. in Computer
Science
from Clemson University in 2003. His research interests include software
testing,
runtime verification of software, software maintenance and model-based
software
development. Peter is a member of the ACM, the ACM SIGSOFT, IEEE Computer
Society, and the International Association of Science and Technology
for Development
(IASTED). He can be reached at clarkep@cs.fiu.edu.
See also http://www.cs.fiu.edu/~clarkep.
Brian A. Malloy is an associate
professor in the department of Computer Science
at Clemson University. Brian’s research focus is software engineering
and compiler
technology. He has investigated issues in software validation, testing
and program
representations to facilitate validation and testing. He has applied
software engineering
to parser development, especially as applied to the construction of
a parser and
front-end for C++. In addition, he has developed techniques to validate
contracts
for C++ applications, including the development of an extended form
of class invariants,
temporal invariants. He has investigated issues in class-based testing
and has
developed a parameterized cost model to provide an integration order
for class-based
testing f C++ applications. Brian has also been active in software
visualization,
especially applied to visualization of UML models. malloy@cs.clemson.edu.
See also http://www.cs.clemson.edu/~malloy.
Cite this article as follows:Peter J. Clarke and Brian A. Malloy: "A
Taxonomy of OO Classes to Support the Mapping of Testing Techniques
to a Class",
in Journal of Object Technology, vol. 4, no. 5, July-August,
pp. 95-115 http://www.jot.fm/issues/issue_2005_07/article2
|