Copyright © 1998 Sita Ramakrishnan, Monash University All rights reserved

Light Views

HomeCase StudiesOO TheoryHelp

Object Oriented Testing Techniques

Class Testing

Class testing is the initial testing phase in the class life cycle. A class may be reused as a component in a variety of applications over time. It must be tested in isolation to check its validity as a unit.

The test suite for a class can be defined by first testing each of the routines (methods) in it. The suite is then extended to include test cases that provide interaction testing in which methods that call other methods in the class and those that access the same class data are tested together. Use the preconditions and postconditions in the routines to guide you in the development of test cases for the individual methods.

Class testing includes two forms of testing: specification-based and program-based testing. Specification-based testing treats the class as a black box. It is intended to determine whether the class is performing according to its specification. For example, specification testing for a Stack class should ensure that the Last-In-First-Out (LIFO) policy is being enforced. Program-based testing considers the implementation of the class. The testing is intended to check the correctness in coding. For example, in the Stack class, the test suite must have test cases for all the methods to check for appropriate behaviour.

Specification-Based Testing

Specification-based testing includes both class specification and method specification.

Class Specification

Class specification includes the specifications of all the methods in the class and a broader statement of the concept that the class is intended to represent. For example, a Stack class would include specifications for the method push and pop, but these specifications do not convey how these operations behave when working together in a class. The specification for push would describe how a value is added to the "top" of a stack but would not say anything about deletions. The specification for pop would not state how the deleted item had been inserted on a stack. Only in the class-level specification is the LIFO idea represented. Method specifications lack support for the full semantics of a class, as the pre and post conditions of a method captures only the behavioural requirements for that method.

The specification of a class is the exported features of class. Subclasses will see an expanded interface, which includes both the public and protected features. All the features of a class (exported and secret) must be tested.

Method Specification

The medthod specification is defined by its precondition and postcondition as well as by its signature. Based on the preconditions, test cases are selected to produce outputs.

Program-Based Testing

The program-based testing of a class will test all its methods and will test the class as a unit. The test plan will consider the coding in individual methods in isolation and then consider the interaction between methods. Each method can be tested over its domain of inputs but the interactions between methods need to be tested before testing is adequate. Method testing involves checking that the method performs as specified. The class must be exercised over a representative set of its states.

Methods in Isolation

The first level of program-based testing considers each method in isolation. Messages sent to other objects are ignored and replaced by stubs that return appropriate values. Test data is selected to ensure adequate coverage of the code in the class.

Methods in Integration

This level of testing considers the interaction of one method calling another within the same class (intraclass) and messages from one class to another (interclass). Testing methods in isolation checks the quality of their implementation but may not highlight any subtle problem of sequencing. Test cases that invoke these interactions are included in the test suite to enable the developer to check that the interaction is handled correctly. Exercising all major states of the class is an important adequacy criterion for this type of testing.

Integration Testing

Testing a new class also tests the integration of those classes that participate in its definition. is-a, is-part-of, and refers-to relations establish dependencies between classes which require testing. They also imply an ordering to the testing of several classes. Test basic classes first, then test classes that use the basic classes, and so on, using a layered approach.

The current testing can be limited to domain testing when a message is sent from the class being tested to an instance of another class which has already been tested. The message is checked to make sure that the actual parameters come from the appropriate domains. Integration testing in object-oriented systems requires that classes be brought together that were not specifically written for use in the current application. This implies that the coordination between these classes needs to be tested.

Hierarchical Incremental Testing

The structure of the application class definitions can be used to support an approach that reuses test cases from one class to another. First, test the base classes, which have no ancestors. Reuse existing test cases from the test suites of the parent class(es) in the test suite of a subclass. This technique incrementally develops the test suite for a class based on its hierarchical relationship with its ancestors and is thus termed hierarchical incremental testing. Complications exist when testing deferred/abstract methods where no implementation exists, and deferred/abstract classes, where the class cannot be instantiated. There can also complications testing secret or private features.

 

Hierarchical incremental testing allows the testing of a subclass to begin with the test cases of the ancestor classes. Develop the test suite for a subclass by noting those parts of the class that are new. Eliminate test cases from the ancestor's test suite, which need not be retested. By treating specification, program-based and integration testing separately, one has three distinct sets of test cases from which to select those that require retesting. Other test cases may be added when new features are defined, either as additions to existing classes or as redefinitions of existing features.

Inheritance Regression Testing

Regression testing is a fault-based testing approach. It involves repeating test cases that uncovered faults in a subclass or previous software version in order to detect errors in the current software version. When new software, built from old versions of source, contains previously fixed errors, the code is said to have "regressed", hence the term regression testing .

Basic regression testing checks for faults that were fixed previously, however other errors may still be present. Developers may have access to bug report logs from a previous iteration of the project which highlight the kinds of errors and areas of code (e.g. complex algorithm, complex interface, boundary conditions, rarely executed piece of code such as the year 2000 problem) that warrant more attention.

A robust regression test incorporates knowledge about common areas where software faults occur. A good robust set of regression tests is designed to uncover related faults in the software in addition to testing for the old errors, as sof tware faults may be structurally or functionally related. Regression tests complement behavioural (functional) and structural (code based) testing.

Often, developers do not employ robust regression techniques to create and track tests. A case in point appears to be the new automated Victorian Met Tram ticketing system, reported in "the Four Corners Program, ABC TV, 20/4/98 titled "On the Right Tracks". Mr. Batchelor, shadow transport minister reported that the new Met Tram ticketing system had some teething problems and that it appeared that a suite of tests to track revenues across various parts of the system were having about a 10% success rate. It seemed that one of the business requirements to track patronage and revenue across various parts of the system was not working. This aspect of the system had to be fixed, and regression testing was needed to ensure that the system tests failed if any aspect of the previous faults still existed. The tests had to also provide good code-based coverage including code that interacted with previously faulty code. Finally, it had to also verify that the output data from the tests were correct.


Funded by Committee of University Teaching And Staff Development (CUTSD) through DEETYA, 1998

 


Disclaimer