Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com
Answertopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions
Privacy Policy

  




 

 

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

The TestSuite Framework

Some automated C++ unit test tools are available on the World Wide Web for download, such as CppUnit.[24] Our purpose here is not only to present a test mechanism that is easy to use, but also easy to understand internally and even modify if necessary. So, in the spirit of Do The Simplest Thing That Could Possibly Work, [25] we have developed the TestSuite Framework, a namespace named TestSuite that contains two key classes: Test and Suite.

The Test class is an abstract base class from which you derive a test object. It keeps track of the number of passes and failures and displays the text of any test condition that fails. You simply to override the run( ) member function, which should in turn call the test_( ) macro for each Boolean test condition you define.

To define a test for the Date class using the framework, you can inherit from Test as shown in the following program:

//: C02:DateTest.h
#ifndef DATETEST_H
#define DATETEST_H
#include "Date.h"
#include "../TestSuite/Test.h"
 
class DateTest : public TestSuite::Test {
Date mybday;
Date today;
Date myevebday;
public:
DateTest(): mybday(1951, 10, 1), myevebday("19510930") {}
void run() {
testOps();
testFunctions();
testDuration();
}
void testOps() {
test_(mybday < today);
test_(mybday <= today);
test_(mybday != today);
test_(mybday == mybday);
test_(mybday >= mybday);
test_(mybday <= mybday);
test_(myevebday < mybday);
test_(mybday > myevebday);
test_(mybday >= myevebday);
test_(mybday != myevebday);
}
void testFunctions() {
test_(mybday.getYear() == 1951);
test_(mybday.getMonth() == 10);
test_(mybday.getDay() == 1);
test_(myevebday.getYear() == 1951);
test_(myevebday.getMonth() == 9);
test_(myevebday.getDay() == 30);
test_(mybday.toString() == "19511001");
test_(myevebday.toString() == "19510930");
}
void testDuration() {
Date d2(2003, 7, 4);
Date::Duration dur = duration(mybday, d2);
test_(dur.years == 51);
test_(dur.months == 9);
test_(dur.days == 3);
}
};
#endif // DATETEST_H ///:~
 

Running the test is a simple matter of instantiating a DateTest object and calling its run( ) member function:

//: C02:DateTest.cpp
// Automated testing (with a framework).
//{L} Date ../TestSuite/Test
#include <iostream>
#include "DateTest.h"
using namespace std;
 
int main() {
DateTest test;
test.run();
return test.report();
}
/* Output:
Test "DateTest":
Passed: 21, Failed: 0
*/ ///:~
 

The Test::report( ) function displays the previous output and returns the number of failures, so it is suitable to use as a return value from main( ).

The Test class uses RTTI[26] to get the name of your class (for example, DateTest) for the report. There is also a setStream( ) member function if you want the test results sent to a file instead of to the standard output (the default). You ll see the Test class implementation later in this chapter.

The test_( ) macro can extract the text of the Boolean condition that fails, along with its file name and line number.[27] To see what happens when a failure occurs, you can introduce an intentional error in the code, for example by reversing the condition in the first call to test_( ) in DateTest::testOps( ) in the previous example code. The output indicates exactly what test was in error and where it happened:

DateTest failure: (mybday > today) , DateTest.h (line 31)
Test "DateTest":
Passed: 20 Failed: 1
 

In addition to test_( ), the framework includes the functions succeed_( ) and fail_( ), for cases where a Boolean test won t do. These functions apply when the class you re testing might throw exceptions. During testing, create an input set that will cause the exception to occur. If it doesn t, it s an error and you call fail_( ) explicitly to display a message and update the failure count. If it does throw the exception as expected, you call succeed_( ) to update the success count.

To illustrate, suppose we modify the specification of the two non-default Date constructors to throw a DateError exception (a type nested inside Date and derived from std::logic_error) if the input parameters do not represent a valid date:

Date(const string& s) throw(DateError);
Date(int year, int month, int day) throw(DateError);
 

The DateTest::run( ) member function can now call the following function to test the exception handling:

void testExceptions() {
try {
Date d(0,0,0); // Invalid
fail_("Invalid date undetected in Date int ctor");
} catch(Date::DateError&) {
succeed_();
}
try {
Date d(""); // Invalid
fail_("Invalid date undetected in Date string ctor");
} catch(Date::DateError&) {
succeed_();
}
}
 

In both cases, if an exception is not thrown, it is an error. Notice that you must manually pass a message to fail_( ), since no Boolean expression is being evaluated.

Thinking in C++ Vol 2 - Practical Programming
Prev Home Next

 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire