The changes made to CppUnit are:
CppUnitW 1.2: includes source and documentation
for VC++ and Unix. (200Ko).
CppUnitW 1.1: includes source and documentation.
(233Ko).
Download and unzip your version of CppUnitW.Compiling the samples
The physical layout is as follow:
CppUnit/: The directory contained in the zip file. doc/: Contains some documentation about unit testing. index.html This page (without images). examples/: Some examples. Example.dsw VC++ workspace for the hierarchy example. hierarchy/: Source of a text test runner based example. msvc6/: VC++ specific examples (use the graphic TestRunner) HostApp/: Source of a graphic test runner based example. HostApp.dsw Workspace to compile the graphic test runner based example. Lib/: Target directory for the compiled dll and libraries. src/: Source (cppunit should move there...) cppunit/: Source for the CppUnit library and private headers. CppUnit.dsw Workspace to compile the cppunit static library. msvc6/: Source specific to VC++ platform. TestRunner/: Source of the graphic test runner dynamic library. TestRunner.dsw Workspace to compile the graphic test runner.Now, to run your first sample:
The top combo box show the most recently used test.
You select a test using the button Browse (that's a new feature).
When a test is run using the Run button, the color of the progress
bar indicates if a test has failed (red) or not (green). The list below
show details about the failed test.
The autorun check box indicates is the most recently
used test must be automatically run when the test runner is opened.
All those settings are stored in the host application
registry in the CppUnit section (allowing per application setting and more
recently used test list).
Pressing the spacebar will run the selected test.
Pressing 'Q' will send a WM_QUIT message
to the host application, which should result in exiting the host application.
The above dialog appears when you click on Browse button. You select the test you want to run with this dialog. You can explore the hierarchy of tests.
One of the major improvement of this version over other is the creation of test case.Creating test case
For the first comer who had never used cppunit, I would recommend to first try using the macro, since it's easier to set up, then switch to the template helper such as TestSuiteBuilder once they get a feeling of how it works. Macros makes it easy, but you can't build upon the existing framework using them.
First, you must create a class that inherit CppUnit::TestCase, the base class for all test case:The way of macros
Then, you declares the test suite for this test case, and all the methods to run for this test case:#include <cppunit/TestCase.h> #include <cppunit/extensions/HelperMacros.h>class ExampleTestCase : public CppUnit::TestCase {
The macro CU_TEST_SUITE actually declares a bunch of typedef, implements the static method suite() which returns the suite for this test case, and start implementing a template method named registerTests.CU_TEST_SUITE( ExampleTestCase ); CU_TEST( example ); CU_TEST( anotherExample ); CU_TEST( testAdd ); CU_TEST( testDivideByZero ); CU_TEST( testEquals ); CU_TEST_SUITE_END(); public: ...
What do we have at that point:
#include "ExampleTestCase.h"
CU_TEST_SUITE_REGISTRATION( ExampleTestCase );
The macro CU_TEST_SUITE_REGISTRATION defines a static variable of type CppUnit::AutoRegisterSuite, with the specified class type. When this variable will be initialized (at static initialization time), it will retrieve the suite() of the class and register it to the TestRegistry. The parameter is the type of the test case, for example, CU_TEST_SUITE_REGISTRATION( ChessTest<Chess> ) is used to register a template test case.
This great thing about this is that it works just fine with template! No more TestCaller instantiation of the death.
There is one thing that remaining: how to sub-class a test case ? The macros makes it very easy, instead of using CU_TEST_SUITE to declare the suite, you do as follow:
As you can see, you must use the macro CU_TEST_SUB_SUITE and specify the base class as well as the test case class. That's all, it's all done!class SimpleSubTest : public SimpleTest { CU_TEST_SUB_SUITE( SimpleSubTest, SimpleTest ); CU_TEST( testAdd ); CU_TEST( testSub ); CU_TEST_SUITE_END(); public: ...
Since your reading this, your are familiar with CppUnit architecture. One of the thing I found frustrating was the building of suite. Here you have your traditional template test case:The way of templates
#include <cppunit/TestCase.h>Here we created a test case for a string class. The test case itself is a template parametrized with the type of character used by the string.
#include <cppunit/TestSuite.h>template<typename CharType>
class StringTest : public TestCase
{
public:
static CppUnit::TestSuite *suite();void testAppend();
void testLength();
};
The static method suite() returns a suite
containing the test to run for this test case. Here is the typical way
this method is implemented:
template<typename CharType>I found that very hard to read and maintain, so I created a helper template class to make it easier. This is the TestSuiteBuilder. Here is how to use it:
CppUnit::TestSuite *
StringTest<CharType>::suite()
{
// Constructs the suite naming it after the test case class name...
CppUnit::TestSuite *suite = new CppUnit::TestSuite( StringTest<CharType> );// adds test caller to the suite for each of the test method.
suite->addTest( new CppUnit::TestCaller< StringTest<CharType> >(
"testAppend",
&StringTest<CharType>::testAppend ) );
suite->addTest( new CppUnit::TestCaller< StringTest<CharType> >(
"testLength",
&StringTest<CharType>::testLength ) );
}
#include <cppunit/extensions/TestSuiteBuilder.h>As you can see it much readable...[...]
template<typename CharType>
CppUnit::TestSuite *
StringTest<CharType>::suite()
{
CppUnit::TestSuiteBuilder< StringTest<CharType> > suite;suite.addTestCaller( "testAppend", testAppend );
suite.addTestCaller( "testLength", testLength );
return suite.takeSuite();
}
You still have to pass the suite to the test runner. There is two ways to do that:
You can use the TestFactoryRegistry:
#include <cppunit/extensions/AutoRegisterSuite.h>This will create a TestSuiteFactory for the specified class and register it to the TestFactoryRegistry.static CppUnit::AutoRegisterSuite< StringTest<CharType> > suite__;
Now, we still need to run those test case. This is a really simple thing to do. You need to plug a bunch of code in your application. I like to do this in the InitInstance(), after everything is initialized, and with a magic key. In the HostApp example, it is done in CHostAppDoc::OnNewDocument().Using TestRunner from your application
Here is what you need to do if you are using the TestFactoryRegistry (the CU_TEST_SUITE_REGISTRATION macro or the template AutoRegisterSuite):
#include <TestRunner/TestRunner.h> #include <cppunit/extensions/TestFactoryRegistry.h> [...]
CHostAppDoc::OnNewDocument() { TestRunner runner; runner.addTest ( CppUnit::TestFactoryRegistry::getRegistry().makeTest() ); // open and run the test runner dialog... runner.run(); [...] }And if you want to do it the traditional way:
#include <TestRunner/TestRunner.h> #include "StringTest.h" #include "ExampleTestCase.h"
[...]
CHostAppDoc::OnNewDocument() { TestRunner runner; runner.addTest( StringTest<char>::suite() ); runner.addTest( StringTest<wchar_t>::suite() ); runner.addTest( ExampleTestCase::suite() ); runner.run(); [...] }
For the includes, there is two ways:Compiling with CppUnit and TestRunner
Warning: when running your application, the TestRunnerd.dll which is in the Lib directory need to be the path (see ::LoadLibrary documentation for loading order). I usually ensure that the DLL is in the debug directory by adding a post build "copy" command. See Project Settings/Post-build Step from the HostApp example for detail.