Size: 3702
Comment: Typos
|
Size: 6956
Comment: Fixtures, Callers, Suites, and Runners
|
Deletions are marked like this. | Additions are marked like this. |
Line 25: | Line 25: |
Suppose we write a class `Complex` for dealing with complex numbers. In the following code, the `operator+` intentionally contains a bug: | Suppose we are developing a class `Complex` for dealing with complex numbers. In the following code, the `operator+` intentionally contains a bug: |
Line 111: | Line 111: |
As you can see, the third assertion failed, which detects the bug in our `operator+`. 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. |
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 Test``Fixtures, Test``Callers, Test``Suites, and Test``Runners. 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: {{{ // The class complex we are developing, having a bug in operator+ 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) {} }; 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); } // A test suite for Complex, run by a runner #include <cppunit/TestFixture.h> #include <cppunit/TestSuite.h> #include <cppunit/TestCaller.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; } }; #include <cppunit/ui/text/TestRunner.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 }}} |
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
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:
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) {} }; 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:
#include <cppunit/TestCase.h> class ComplexNumberTest : public CppUnit::TestCase { public: 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)); } }; int main() { ComplexNumberTest myTest("My first CppUnit test"); myTest.runTest(); }
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.
Compiling and running
Suppose we put all the above code into one file ComplexNumberTest.cpp. Then the following makefile 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 executable from a .cpp-file %: %.cpp ${CC} -o $@ $< ${CXXFLAGS} ${INCLS} ${LIBDIRS} ${LIBS} runtest: ComplexNumberTest export LD_LIBRARY_PATH=/var/tmp/cppunit/install/lib && ./ComplexNumberTest
Note that CppUnit needs the library ld.so in the linking step.
Now we can compile and run the program:
$ make runtest 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 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: 1457 Aborted ./ComplexNumberTest
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:
// The class complex we are developing, having a bug in operator+ 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) {} }; 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); } // A test suite for Complex, run by a runner #include <cppunit/TestFixture.h> #include <cppunit/TestSuite.h> #include <cppunit/TestCaller.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; } }; #include <cppunit/ui/text/TestRunner.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