TESTING
SOFTWARE QA
RESOURCES

Object Oriented Programming requires its own sets of test design strategies and defect management procedures.

Software used for Test and Measurement Instrumentation Control greatly benefits from an object oriented design.

An object oriented software system is a set of objects containing a number of operations (methods). Through the invocation of methods the objects interact by sending and receiving messages. For testing object oriented code it is convenient to take the view that an object oriented system or design has class diagrams (structure models), sequence and state diagrams (causal or dynamic models) and algorithmic descriptions or activity diagrams (transformational models). The structure is reflected in the classes of a system, causality in the object call sequence, and transformations in the methods and their algorithms. From this testing point of view, object oriented programs are models that capture the structural, causal, and transformational views of the situation being modeled. Testing can then be broken down into these three types:

Structural Testing: deals with classes, objects and their combinations.

Causal Testing: deals with the call sequences of the program and how individual objects transition from one state to another state. It can also be call state-based testing. Use of state diagrams and other dynamic model artifacts would allow us to conduct sequential testing between classes (who calls whom?) and modal testing within a given class (how many different states are logically allowed and entered into the objects of this class?)

Transformational Testing: closest to the traditional methods of testing non-object oriented code. It concentrates on the correctness of how input values are turned into output values. It deals with the algorithmic correctness of the code within a method or between methods in a single object or indeed between objects.

These three test approaches together do not imply necessarily that all defects can be found but they do together cover the largest set of likely defects. Even performing these approaches fully there will be further test cases that need to be added.

Testing approaches to Object Oriented Programs can also be described in terms of macro and micro scale levels of testing:

Macro Level: Classes; Clusters of classes or components; Groups of interacting components that provide a given and well-defined service (a framework) and ultimately, the system.

Micro level: Method interaction within an object; Classes, which can be of three kinds: bases classes, derived classes, and reusable, generic, and abstracted class objects, and, Class hierarchies.

A class is a template and it cannot be tested because there is no class artifact in the compiled version of a program. There are instead instances (objects) created from the class template. However, since the classes must be tested it is necessary to determine what can be done in terms of testing proxies for:

Class testing and Class hierarchy testing: should be performed against detailed design (that describes the class, its responsibilities, and its modes) using objects.

Method testing: Methods are tested against detailed design in terms of inputs -transformation - outputs, pre- and post-conditions, and method invariants, using algorithms and assertions.

Module testing (including regression): Module testing should be conducted against the architecture using High level design.

System Testing: In general, System testing should be conducted against a Specification using Requirement scenarios and Acceptance cases. However, these documents are not available to the MVC project.

In general - in isolation - a class is correct if:
  1. All its intended instances can be correctly generated;
  2. The attribute value set of all objects created from the class would at any time represent a valid state of the object;
  3. Each and every routine within these objects correctly alters the representation of the corresponding object.

There is no single testing strategy that can conclusively show that all these conditions have been satisfied. Testing approaches do exist that can raise confidence in each of the three conditions.

Testing for correct generation of instances: In most object oriented languages classes have within them a provision for instantiation called constructors. These are in the form of routines. They may require initialization parameters and there might be more than one constructor for any one class.

Tests should be created to determine that each and every constructor can generate an intended instance of the class. Also, in the case of multiple constructors, the generation of an intended instance of the class is not order dependent unless specifically required. A test case (perhaps as a test class, or perhaps through Simple Test scripts) can be written that tests the following conditions:

  1. All attributes have been initialized correctly.
  2. The order of initialization is correct.

A simple structural way to check the self-consistency of the constructors is to follow the procedure:

  1. Identify all constructors for the class under test;
  2. Start with the first constructor;
  3. Instantiate the class using this constructor;
  4. Check the values of each attribute using an accessor (get[x]) routine;
  5. Go to the next constructor until all are done;
  6. Create several random orderings of constructor calls;
  7. Compare the initialized attribute values after each construction of
    each object using any given constructor with all other such
    instantiations from other sequences. Ensure they are all consistent.

However, this approach has the following problems:

  1. The available interface may disallow access to some attributes needed for state determination;
  2. The access methods (get methods) may produce side effects;
  3. The access methods may contain bugs and not report the correct value.

Testing for Correct Attribute valuescan be achieved through state based testing of attribute values.