Example Tester

ECE 250 students are not required to know this.

Suppose we have written a class Array which allows us to store objects integers in order. The interface of this class could be:

#ifndef ARRAY_H
#define ARRAY_H

#include "Exception.h"

class Array {
        private:
                int *array;
                int count;

        public:
                Array( int = 10 );
                ~Array();

                bool empty() const;
                int size() const;
                int get( int ) const;
                bool member( int ) const;
                void print() const;

                void insert( int );
                bool remove( int );
};

#endif

A not-so-wondeful implementation of this class is shown in the src/ directory.

We could determine that we would want to write the following commands to test the various functions. In this table, n and m are integers and b represents 1 (true) or 0 (false).

CommandTests...
newthe default constructor
new(n) nthe constructor with an argument n
empty bempty() == b
size nsize() == n
get m nget( m ) == n
member n bmember( n ) == b
printprint the elements in order separated by dashes
insert ninsert( n ) succeeds
insert-overflow ninsert( n ) throws an overflow exception
remove n bremove( n ) == b
deletethe destructor

The first and last are provided by the default Tester class, however, now we have to create two additional files: an ArrayDriver.cpp file and a ArrayTester.h file where we implement the class ArrayTester (derived from Tester). These are implemented in the tst/ directory.

As shown on the Drivers link, the ArrayDriver.cpp can be implemented as follows:


/****************************************************
 * Class:   ArrayDriver
 * Author:  Douglas Wilhelm Harder
 *
 * Copyright (c) 2006 by Douglas Wilhelm Harder.  All rights reserved.
 ****************************************************/

#include "ArrayTester.h"

int main() {
	ArrayTester tester;

	cout << "Starting Test Run" << endl;

	tester.run();

	cout << "Finishing Test Run" << endl;
	dwharder/Algorithms_and_Data_Structures::allocation_table.summary();

	return 0;
}

As shown on the Derived Tester Classes link, we can create a skeletal derived class as follows:


/*************************************************
 * ArrayTester
 * Author:  Douglas Wilhelm Harder
 *
 * A class for testing our silly Array class
 *
 * Copyright (c) 2006 by Douglas Wilhelm Harder.  All rights reserved.
 *************************************************/

#ifndef ARRAYTESTER_H
#define ARRAYTESTER_H

#include "Tester.h"
#include "Array.h"

#include <iostream>

using namespace std;

class ArrayTester:public Tester<Array> {
    public:
        ArrayTester( Array *obj = 0, int c = 1 ):Tester<Array>( obj, c ) {
            // empty constructor
        }
};

/****************************************************
 * void process()
 ****************************************************/

void Tester<Array>::process() {
    if ( false ) {
        // do nothing
    } else {
        cout << command << ": Command not found." << endl;
    }
}
#endif

Now, for each test we would like to perform (as listed in the above array, we implement an appropriate entry. We will cover three of the cases here, while all are implemented in the file in the tst/ArrayTester.h file.

new(n) n

Here, we read in one parameter and call the constructor:

    if ( "command" == "new(n)" ) {
        int n;
        cin >> n;

        object = new Array( n );

        cout << "Okay"  << endl;

size n

In this case, we check that the return value matches what we expect it to be. From the template, we generate:

    } else if ( command == "size" ) {
        int expected_size;
        cin >> expected_size;

        int actual_size = object -> size();

        if ( actual_size == expected_size ) {
            cout << "Okay" << endl;
        } else {
            cout << "Failure in size(): expecting the value '"
                 << expected_size << "' but got '"
                 << actual_size << "'" << endl;
        }

print

This tests functionality which prints the entries out separated by dashes. In this case, we must add an end-of-line character:

    if ( "command" == "print" ) {
        object -> print();

        cout << endl;

insert-overflow n

Here we are trying to catch an overflow exception. Using the template:

    } else if ( command == "insert-overflow" ) {
        int n;
        cin >> n;

        try {
            object -> insert( n );
            cout << ": Failure in insert(): expecting an exception but did not"
                 << endl;
        } catch ( overflow ) {
            cout << "Okay" << endl;
        }

The remaining tests are implemented in the ArrayTester.h file.

Running Tests

First, we would compile the cpp file. In Unix, this would mean executing:

$ g++ ArrayDriver.cpp

The executable is a file called a.out.

We can now run some tests. Following the above format, we could write the testing file:

new(n) 5
size 0
empty 1
insert 7
size 1
empty 0
insert 3
insert 5
insert 1
insert 2
print                   // should be 1-2-3-5-7
remove 2 1              // successfully remove 2
remove 99 0             // cannot remove 99
insert 23 
print                   // should be 1-3-5-7-23
size 5
insert-overflow 32
delete

Note: the comments are there for your info and should not be included in the actual testing file.

If we execute a.out and redirect this file as input, we get:

$ ./a.out < test01.txt 
Starting Test Run
1 % Okay
2 % Okay
3 % Okay
4 % Okay
5 % Okay
6 % Okay
7 % Okay
8 % Okay
9 % Okay
10 % Okay
11 % 1-2-3-5-7
12 % Okay
13 % Okay
14 % Okay
15 % 1-3-5-7-23
16 % Okay
17 % Okay
18 % Okay
19 % Exiting...
Finishing Test Run
Memory allocated minus memory deallocated: 0

Thus, our implementation would pass this test. This test file is also located in the tst/ directory.

Copyright ©2006 by Douglas Wilhelm Harder. All rights reserved.