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).
Command | Tests... |
---|---|
new | the default constructor |
new(n) n | the constructor with an argument n |
empty b | empty() == b |
size n | size() == n |
get m n | get( m ) == n |
member n b | member( n ) == b |
print the elements in order separated by dashes | |
insert n | insert( n ) succeeds |
insert-overflow n | insert( n ) throws an overflow exception |
remove n b | remove( n ) == b |
delete | the 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.
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;
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; }
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;
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.
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.