Size: 8108
Comment:
|
Size: 8817
Comment: Examples split into correct header/implementation files
|
Deletions are marked like this. | Additions are marked like this. |
Line 4: | Line 4: |
The project's homepage is http://sourceforge.net/projects/cppunit. |
|
Line 28: | Line 30: |
// files Complex.h/Complex.cpp | // file Complex.h |
Line 37: | Line 39: |
}}} {{{ // file Complex.cpp #include "Complex.h" |
|
Line 51: | Line 59: |
Now let us write a Cpp``Unit test case for this class: {{{ // file ComplexNumberTest.h/.cpp |
Now let us write a Cpp``Unit test case for this class. For this, we have to subclass the `TestCase` class and to override the method `runTest()`. To check a value, we call `CPPUNIT_ASSERT(bool)` and pass in an expression that is true if the test succeeds. {{{ // file ComplexNumberTest.h |
Line 57: | Line 68: |
#include "Complex.h" | |
Line 61: | Line 71: |
ComplexNumberTest( std::string name ) : CppUnit::TestCase( name ) {} void runTest() { CPPUNIT_ASSERT( Complex (10, 1) == Complex (10, 1) ); CPPUNIT_ASSERT( !(Complex (1, 1) == Complex (2, 2)) ); CPPUNIT_ASSERT( Complex (1, 2) + Complex(3, 4) == Complex (4, 6)); } |
ComplexNumberTest( std::string name ); void runTest(); |
Line 70: | Line 75: |
{{{ // file ComplexNumberTest.cpp #include "Complex.h" #include "ComplexNumberTest.h" ComplexNumberTest::ComplexNumberTest( std::string name ) : CppUnit::TestCase( name ) {} void ComplexNumberTest::runTest() { CPPUNIT_ASSERT( Complex (10, 1) == Complex (10, 1) ); CPPUNIT_ASSERT( !(Complex (1, 1) == Complex (2, 2)) ); CPPUNIT_ASSERT( Complex (1, 2) + Complex(3, 4) == Complex (4, 6)); } }}} The main program creates a `TestCase` object and calls its `runTest()` method: |
|
Line 85: | Line 110: |
For this, we have to subclass the `TestCase` class and to override the method `runTest()`. To check a value, we call `CPPUNIT_ASSERT(bool)` and pass in an expression that is true if the test succeeds. | |
Line 90: | Line 114: |
Suppose we put all the above code into one file `ComplexNumberTest.cpp`. Then the following makefile will do the job for us: | The following makefile based on implicit rules will do the job for us: |
Line 97: | Line 121: |
# Implicit rule: How to make an executable from a .cpp-file %: %.cpp ${CC} -o $@ $< ${CXXFLAGS} ${INCLS} ${LIBDIRS} ${LIBS} |
# Implicit rule: How to make an .o-file from a .cpp-file %.o: %.cpp ${CC} -c $< ${CXXFLAGS} ${INCLS} # Implicit rule: How to make an executable from .o-files %: %.o ${CC} -o $@ $? ${LIBDIRS} ${LIBS} runComplexNumberTest: runComplexNumberTest.o ComplexNumberTest.o Complex.o |
Line 103: | Line 133: |
Line 112: | Line 141: |
cc -o ComplexNumberTest ComplexNumberTest.cpp -I/var/tmp/cppunit/install/include/ -L/var/tmp/cppunit/install/lib -lcppunit -ldl export LD_LIBRARY_PATH=/var/tmp/cppunit/install/lib && ./ComplexNumberTest |
cc -c runComplexNumberTest.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -c ComplexNumberTest.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -c Complex.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -o runComplexNumberTest runComplexNumberTest.o ComplexNumberTest.o Complex.o -L/var/tmp/cppunit/install/lib -lcppunit -ldl export LD_LIBRARY_PATH=/var/tmp/cppunit/install/lib && ./runComplexNumberTest |
Line 118: | Line 150: |
/bin/sh: line 1: 1457 Aborted ./ComplexNumberTest | /bin/sh: line 1: 10793 Aborted ./runComplexNumberTest make: *** [runtest] Error 134 |
This document describes very shortly how to install the [http://sourceforge.net/projects/cppunit/ CppUnit] framework under Unix and how to write and run a very simplistic test case. This should get you started with using CppUnit, so that you can follow and try out the examples given in the [http://cppunit.sourceforge.net/doc/lastest/cppunit_cookbook.html CppUnit CookBook].
Installing
The project's homepage is http://sourceforge.net/projects/cppunit.
Download the latest version of CppUnit from http://downloads.sourceforge.net/cppunit/cppunit-1.12.1.tar.gz.
Let us install it under /var/tmp/cppunit/install:
$ cd /var/tmp/ $ mv ~/cppunit-1.12.1.tar.gz . $ tar xzf cppunit-1.12.1.tar.gz $ ln -s cppunit-1.12.1 cppunit $ cd cppunit $ ./configure --prefix=`pwd`/install $ make $ make check $ make install
Writing a simplistic test case
Suppose we are developing a class Complex for dealing with complex numbers. In the following code, the operator+ intentionally contains a bug:
// file Complex.h class Complex { friend bool operator==(const Complex& a, const Complex& b); friend Complex operator+(const Complex& a, const Complex& b); double real, imaginary; public: Complex( double r, double i = 0 ) : real(r), imaginary(i) {} };
// file Complex.cpp #include "Complex.h" bool operator==( const Complex &a, const Complex &b ) { return a.real == b.real && a.imaginary == b.imaginary; } Complex operator+( const Complex &a, const Complex &b ) { // BUG! imaginary part should be 'a.imaginary + b.imaginary' return Complex(a.real + b.real, a.imaginary + b.real); }
Now let us write a CppUnit test case for this class.
For this, we have to subclass the TestCase class and to override the method runTest(). To check a value, we call CPPUNIT_ASSERT(bool) and pass in an expression that is true if the test succeeds.
// file ComplexNumberTest.h #include <cppunit/TestCase.h> class ComplexNumberTest : public CppUnit::TestCase { public: ComplexNumberTest( std::string name ); void runTest(); };
// file ComplexNumberTest.cpp #include "Complex.h" #include "ComplexNumberTest.h" ComplexNumberTest::ComplexNumberTest( std::string name ) : CppUnit::TestCase( name ) {} void ComplexNumberTest::runTest() { CPPUNIT_ASSERT( Complex (10, 1) == Complex (10, 1) ); CPPUNIT_ASSERT( !(Complex (1, 1) == Complex (2, 2)) ); CPPUNIT_ASSERT( Complex (1, 2) + Complex(3, 4) == Complex (4, 6)); }
The main program creates a TestCase object and calls its runTest() method:
// file runComplexNumberTest.cpp #include "ComplexNumberTest.h" int main() { ComplexNumberTest myTest("My first CppUnit test"); myTest.runTest(); }
Compiling and running
The following makefile based on implicit rules will do the job for us:
INCLS = -I/var/tmp/cppunit/install/include/ LIBDIRS = -L/var/tmp/cppunit/install/lib LIBS = -lcppunit -ldl # note that CppUnit needs libld.so! # Implicit rule: How to make an .o-file from a .cpp-file %.o: %.cpp ${CC} -c $< ${CXXFLAGS} ${INCLS} # Implicit rule: How to make an executable from .o-files %: %.o ${CC} -o $@ $? ${LIBDIRS} ${LIBS} runComplexNumberTest: runComplexNumberTest.o ComplexNumberTest.o Complex.o runtest: runComplexNumberTest export LD_LIBRARY_PATH=/var/tmp/cppunit/install/lib && ./runComplexNumberTest
Note that CppUnit needs the library ld.so in the linking step.
Now we can compile and run the program:
$ make runtest cc -c runComplexNumberTest.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -c ComplexNumberTest.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -c Complex.cpp -Wall -I/var/tmp/cppunit/install/include/ cc -o runComplexNumberTest runComplexNumberTest.o ComplexNumberTest.o Complex.o -L/var/tmp/cppunit/install/lib -lcppunit -ldl export LD_LIBRARY_PATH=/var/tmp/cppunit/install/lib && ./runComplexNumberTest terminate called after throwing an instance of 'CppUnit::Exception' what(): assertion failed - Expression: Complex (1, 2) + Complex(3, 4) == Complex (4, 6) /bin/sh: line 1: 10793 Aborted ./runComplexNumberTest make: *** [runtest] Error 134
As we can see, the third assertion failed, which detects the bug in our operator+.
Fixtures, Callers, Suites, and Runners
Now go on and read the rest of the [http://cppunit.sourceforge.net/doc/lastest/cppunit_cookbook.html CppUnit CookBook] and try out the examples given there. You will learn about TestFixtures, TestCallers, TestSuites, and TestRunners.
In short:
A TestFixture is a set of objects that serves as a base for a set of test cases, together with methods that implement these test cases.
A TestCaller runs a particular method (test case) of a fixture.
A TestSuite runs any number of callers together.
A TestRunner runs a suite and displays its results.
Here is a complete program:
// files ComplexNumberTestSuite.h/.cpp // A test suite for Complex, run by a runner #include <cppunit/TestFixture.h> #include <cppunit/TestSuite.h> #include <cppunit/TestCaller.h> #include "Complex.h" class ComplexNumberTest : public CppUnit::TestFixture { private: Complex *a, *b, *s; public: void setUp() { a = new Complex( 1, 2 ); b = new Complex( 3, 4 ); s = new Complex( 4, 6 ); } void tearDown() { delete a; delete b; delete s; } void testEquality() { CPPUNIT_ASSERT( *a == *a ); CPPUNIT_ASSERT( !(*a == *b) ); } void testAddition() { CPPUNIT_ASSERT( *a + *b == *s ); } static CppUnit::Test *suite() { CppUnit::TestSuite *suiteOfTests = new CppUnit::TestSuite( "ComplexNumberTest" ); suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>( "testEquality", &ComplexNumberTest::testEquality ) ); suiteOfTests->addTest( new CppUnit::TestCaller<ComplexNumberTest>( "testAddition", &ComplexNumberTest::testAddition ) ); return suiteOfTests; } };
// file runTestSuite.cpp #include <cppunit/ui/text/TestRunner.h> #include "ComplexNumberTestSuite.h" int main() { CppUnit::TextUi::TestRunner runner; runner.addTest( ComplexNumberTest::suite() ); //runner.addTest( AnotherTestFixture::suite() ); //runner.addTest( AnExampleTestCase::suite() ); runner.run(); }
The TestRunner will run the tests. If all the tests pass, we shall get an informative message. If any fail, we shall get the following information:
- The name of the test case that failed
- The name of the source file that contains the test
- The line number where the failure occurred
All of the text inside the call to CPPUNIT_ASSERT() which detected the failure
The output of the above program is
..F !!!FAILURES!!! Test Results: Run: 2 Failures: 1 Errors: 0 1) test: testAddition (F) line: 56 ComplexNumberTestSuite.cpp assertion failed - Expression: *a + *b == *s
Helper macros
Implementing the static suite() method in a TestFixture is a repetitive and error prone task. A set of macros have been created to automatically implement this method.
The following code is a rewrite of ComplexNumberTest using these macros:
// file ComplexNumberTestWithMacro.h/.cpp #include <cppunit/extensions/HelperMacros.h> #include "Complex.h" class ComplexNumberTestWithMacro : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( ComplexNumberTestWithMacro ); CPPUNIT_TEST( testEquality ); CPPUNIT_TEST( testAddition ); CPPUNIT_TEST_SUITE_END(); // remainder as in the class above private: Complex *a, *b, *s; public: void setUp() { a = new Complex( 1, 2 ); b = new Complex( 3, 4 ); s = new Complex( 4, 6 ); } void tearDown() { delete a; delete b; delete s; } void testEquality() { CPPUNIT_ASSERT( *a == *a ); CPPUNIT_ASSERT( !(*a == *b) ); } void testAddition() { CPPUNIT_ASSERT( *a + *b == *s ); } };
There are other helper macros, for example, to check that a specific exception is thrown under specific circumstances. Check the documentation.
In the Cookbook, read the sections on the TestFactoryRegistry (which solves the problem of forgetting to add a fixture suite to the test runner - since it is in another file, it is easy to forget) and the section on how to automate post-build checks.