Project Testing

This file is divided into three sections:

  1. For Students
  2. Shortcuts (History)
  3. For Instructors

For Students

Each project will be tested using automated testing software. You have access to the same testing infrastructure which will be used to mark your projects.

Associated with each class you are required to write will be a tester class and (usually) a driver program. The driver uses your class and the tester class to create an interactive environment where you can enter commands to use and test the class you wrote.

Suppose you have written the classes SingleList (saved in the file SingleList.h) and SingleNode (saved in the file SingleNode.h). Together with the Exception.h file you have already used, you would also download the files SingleListTester.cpp, SingleListTester.h, and ece250.h.

Compile the project into an executable and run the executable.

Note to MS Visual Studio users: only allows one file per project to have a int main(). Simply do not add more than one .cpp file to the project and when you need to test the other driver, remove the one currently included in the project and add the other.

The executable driver produces a prompt. At this point, you can enter a command. The available commands are listed at the top of the SingleListTester class, and for convenience, that portion of the file is listed here:

/****************************************************
 * void process()
 *
 * Process the current command.  For singly-linked lists, these include:
 *
 *  Constructors
 *
 *   new             Constructor     create a new instance of the class being tested
 *   delete          Destructor      call delete on the class currently being tested
 *
 *  Accessors
 *
 *   size n          size            test if size() == n
 *   empty b         empty           test if empty() == b
 *   front n         front           test if front() == n
 *   back n          back            test if front() == n
 *   head0           head            test if head() == 0
 *   tail0           tail            test if tail() == 0
 *   member n b      member          test if member( n ) == b
 *
 *   head            head            tests if head() != 0 and if so, creates
 *                                   a SingleNodeTester with the head
 *                                   use exit to return to testing the SingleList class
 *   tail            tail            like head(), but tests tail()
 *                                   with a SingleNodeTester - use exit to return
 *
 *  Mutators
 *
 *   push_front n    push_front      calls push_front( n )
 *   push_back n     push_back       calls push_back( n )
 *   pop_front n     pop_front       tests if pop_front() == n
 *   remove n b      remove          tests if remove( n ) == b
 ****************************************************/

In all cases, n or m represents an integer while b reprsents either 0 (false) or 1 (true).

Interactive Demonstration with SingleList

Suppose you have implemented some of the functions in your class SingleList class and you would like to test them by doing the following:

  1. Creating a new instance of SingleList,
  2. Pushing 38 onto the front of the linked list,
  3. Checking that the front is 38,
  4. Pushing 42 onto the front of the linked list,
  5. Checking that the front is 42,
  6. Pushing 71 onto the back of the linked list,
  7. Checking that the front is still 42,
  8. Deleteing the instance of SingleList, and
  9. Exiting.

For good measure, we will also check what happens if we check if 50 is at the front of the linked list. Anything in red is text which you would type:

C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe
Starting Test Run
1 % new
Okay
2 % push_front 38
Okay
3 % front 38
Okay
4 % push_front 42
Okay
5 % front 42
Okay
6 % push_back 71
Okay
7 % front 42
Okay
8 % front 50
Failure in front(): expecting the value '50' but got '42'
9 % delete
Okay
10 % exit
Okay
Finishing Test Run
Memory allocated minus memory deallocated: 24

Each time the operation is successful, Okay is printed. Otherwise, a useful error message is printed.

File Redirection Demonstration with SingleList

Instead of alwasy interacting with the interpreter, you can simply store all the commands in a file and redirect the file to the executable.

Create a file called test01.txt and place into this file all of the commands you entered manually above (though exit is not necessary):

new
push_front 38
front 38
push_front 42
front 42
push_back 71
front 42
front 50
delete

At the command line, you can now type:

> Project1a.exe < test01.txt

The < tells the operating system to behave as if the contents of the file text01.txt were being entered interactively. This is a process called redirection.

The output of this process is:

C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe < text01.txt
Starting Test Run
1 % Okay
2 % Okay
3 % Okay
4 % Okay
5 % Okay
6 % Okay
7 % Okay
8 % Failure in front(): expecting the value '50' but got '42'
9 % Okay
10 % Exiting...
Finishing Test Run
Memory allocated minus memory deallocated: 24

At this point, we notice one critical bug: the last line indicates that 24 bytes were allocated, but not unallocated when the delete function was called.

If we examine the destructor, we get an idea as to what went wrong:

template <typename Type>
SingleList<Type>::~SingleList() {
}

Each time we pushed something into the singly-linked list, we needed to create a new instance of a SingleNode class. Because we did so, in the destructor, we must delete each of those nodes. If we would fix this, the last line of the output would be:

Memory allocated minus memory deallocated: 0

One thing which is very useful is testing boundary cases. For example, suppose you add one object into a singly linked list and then remove it again. In this case, both the head and the tail should be 0. Thus, we would add an object, remove it, and then check that both the head and the tail are 0. We could do this by running the following sequence of commands:

new
push_front 23
remove 23 1
head0
tail0
delete

You could save this to a file test02.txt and you could test this until the output is:

C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe < test02.txt
Starting Test Run
1 % Okay
2 % Okay
3 % Okay
4 % Okay
5 % Okay
6 % Okay
7 % Exiting...
Finishing Test Run
Memory allocated minus memory deallocated: 0

Shortcuts (History)

It can become very tedious typing push_front twenty times, so simplify this, you can use !! to represent the previous command. You may also use !n to represent the nth command. In this example, !! always represents the previous command, while !5 represents the 5th command, i.e., pop_front.

C:\Documents and Settings\dwharder\My Documents\ece250> Project1a.exe
Starting Test Run
1 % new
Okay
2 % push_front 12
Okay
3 % !! 34
Okay
4 % !! 56
Okay
5 % pop_front 56
Okay
6 % front 34
Okay
7 % !5 34
Okay
8 % !! 12
Okay
9 % size 0
Okay
10 % delete
Okay
11 % exit
Okay
Finishing Test Run
Memory allocated minus memory deallocated: 0

For Instructors

Given a class ClassName which you would like to test, you would create a derived class of the Tester class. A simple driver routine would create an instance of this derived tester and call the member function void run(). Each of these features is linked to in the left column, but is described here more thorougly:

Drivers
A simple function int main() which creates a new tester and calls the member function void run().
Tester
The Tester class which provides the interpreter with a few basic features.
Derived Tester Classes
How to created a derived class from the Tester class in order to test your specific class.
Memory Management
Managing and tracking the users memory allocations and de-allocations by overriding the global new, new[], delete, and delete[].
Example
An example using a given class, the derived testing class, and a simple test.