Chapter 23 Object-Oriented Testing
Overview
This chapter discusses the testing of object-oriented systems. The process of
testing object-oriented systems begins with a review of the object-oriented
analysis and design models. Once the code is written object-oriented testing
(OOT) begins by testing "in the small" with class testing (class operations and
collaborations). As classes are integrated to become subsystems class
collaboration problems are investigated. Finally, use-cases from the OOA model
are used to uncover software validation errors. OOT similar to testing
conventional software in that test cases are developed to exercise the classes,
their collaborations, and behavior. OOT differs from conventional software
testing in that more emphasis is placed assessing the completeness and
consistency of the OOA and OOD models as they are built. OOT tends to focus more
on integration problems than on unit testing. The test plan specification
template from the SEPA web site is applicable to object-oriented testing as
well.
Object-Oriented Testing Activities
- Review OOA and OOD models
- Class testing after code is written
- Integration testing within subsystems
- Integration testing as subsystems are added to the system
- Validation testing based on OOA use-cases
Testing OOA and OOD Models
- Correctness of OOA and OOD models
- syntactic correctness judged by ensuring that proper modeling conventions
and symbolism have been used
- semantic correctness based on the model's conformance to the real world
problem domain
- Consistency of OOA and OOD models
- assess the class-responsibility-collaborator (CRC) model and
object-relationship diagram
- review system design (examine the object-behavior model to check mapping
of system behavior to subsystems, review concurrency and task allocation, use
use-case scenarios to exercise user interface design)
- test object model against the object relationship network to ensure that
all design object contain necessary attributes and operations needed to
implement the collaborations defined for each CRC card
- review detailed specifications of algorithms used to implement operations
using conventional inspection techniques
Assessing the Class Model
- Revisit the CRC model and the object-relationship model
- Inspect the description of each CRC card to determine if a delegated
responsibility is part of the collaborator's definition
- Invert the connection to ensure that each collaborator that is asked for
service is receiving requests from a responsible source
- Using the inverted connections from step 3, determine whether other
classes might be required or whether responsibilities are properly grouped
among classes
- Determine whether widely requested responsibilities might be combined into
a single responsibility
- Steps 1 to 5 are applied iteratively to each class and through the
evaluation of the OOA model
Object-Oriented Testing Strategies
- Unit testing in the OO context
- smallest testable unit is the encapsulated class or object
- similar to system testing of conventional software
- do not test operations in isolation from one another
- driven by class operations and state behavior, not algorithmic detail and
data flow across module interface
- Integration testing in the OO context
- focuses on groups of classes that collaborate or communicate in some
manner
- integration of operations one at a time into classes is often meaningless
- thread-based testing (testing all classes required to respond to one
system input or event)
- use-based testing (begins by testing independent classes first and the
dependent classes that make use of them)
- cluster testing (groups of collaborating classes are tested for
interaction errors)
- regression testing is important as each thread, cluster, or subsystem is
added to the system
- Validation testing in the OO context
- focuses on visible user actions and user recognizable outputs from the
system
- validation tests are based on the use-case scenarios, the object-behavior
model, and the event flow diagram created in the OOA model
- conventional black-box testing methods can be used to drive the validation
tests
Test Case Design for OO Software
- Each test case should be uniquely identified and be explicitly associated
with a class to be tested
- State the purpose of each test
- List the testing steps for each test including:
- list of states to test for each object involved in the test
- list of messages and operations to exercised as a consequence of the test
- list of exceptions that may occur as the object is tested
- list of external conditions needed to be changed for the test
- supplementary information required to understand or implement the
test
OO Test Design Issues
- White-box testing methods can be applied to testing the code used to
implement class operations, but not much else
- Black-box testing methods are appropriate for testing OO systems
- Fault-based testing
- best reserved for operations and the class level
- uses the inheritance structure
- tester examines the OOA model and hypothesizes a set of plausible defects
that may be encountered in operation calls and message connections and builds
appropriate test cases
- misses incorrect specification and errors in subsystem
interactions
- Object-oriented programming brings additional testing concerns
- classes may contain operations that are inherited from super classes
- subclasses may contain operations that were redefined rather than
inherited
- all classes derived from an previously tested base class need to be
thoroughly tested
- using the user tasks described in the use-cases and building the test
cases from the tasks and their variants
- uncovers errors that occur when any actor interacts with the OO software
- concentrates on what the use does, not what the product does
- you can get a higher return on your effort by spending more time on
reviewing the use-cases as they are created, than spending more time on
use-case testing
- Testing surface structure (exercising the structure observable by
end-user, this often involves observing and interviewing users as they
manipulate system objects)
- Testing deep structure (exercising internal program structure - the
dependencies, behaviors, and communications mechanisms established as part of
the system and object design)
Class Level Testing Methods
- Random testing (requires large numbers data permutations and combinations
and can be inefficient)
- Partition testing (reduces the number of test cases required to test a
class)
- state-based partitioning (tests designed in way so that operations that
cause state changes are tested separately from those that do not)
- attribute-based partitioning (for each class attribute, operations are
classified according to those that use the attribute, those that modify the
attribute, and those that do not use or modify the attribute)
- category-based partitioning (operations are categorized according to the
function they perform: initialization, computation, query,
termination)
Inter-Class Test Case Design
- for each client class use the list of class operators to generate random
test sequences that send messages to other server classes
- for each message generated determine the collaborator class and the
corresponding server object operator
- for each server class operator (invoked by a client object message)
determine the message it transmits
- for each message, determine the next level of operators that are invoked
and incorporate them into the test sequence
- Tests derived from behavior models
- test cases must cover all states in the state transition diagram
- breadth first traversal of the state model can be used (test one
transition at a time and only make use of previously tested transitions when
testing a new transition)
- test cases can also be derived to ensure that all behaviors for the class
have been adequately exercised