By sql_lall Before a motor company releases a new car, it must first be tested to make sure the steering, acceleration and brakes function correctly. Before releasing a new medical drug into the market, it undergoes strict testing to ensure it does what it claims with no undesired harm. In the same way, before any software is released into the wild, it should first be subjected to rigorous tests to try to confirm that each section of the code is bug free. Unit testing, popularized as part of the framework for Xtreme Programming, is one possible method for code-testing based on testing every aspect of the code for well-defined behavior. To assist developers, unit testing code has been developed for many different platforms, commonly referred to as xUnit. TCS developers may recognize many listed there, such as jUnit, jsUnit, nUnit, and httpUnit (covered in this feature). cppUnit is the port of this framework for use with C++ projects. Building your unit: Before developing cppUnit code, it must be first built locally. Detailed information is available from the cppUnit wiki build page, and is summarized below. This process applies to those on a Unix machine or running cygwin under Windows:
If you are interested in using cppUnit from Windows using Visual Studio, there will be a .dsw file provided that allows you to test a project in the Post-Build phase. For more information, see the build page linked above. Also available are instructions to build cppUnit within Eclipse. Unit interaction: Unit testing with cppUnit is based around TestFixture instances, each of which contains a suite of test cases. To write some tests of your own, first create a test class that extends publicly from the CppUnit::TestFixture class. Inside that you can then create as many void test methods as you like, performing various assertion tests using the multitude of helpful test macros provided by TestAsserts.h. For example, here is a method which tests the return value of a method multiple times, using most of the available macros: class suiteOfTests : public CppUnit::TestFixture { /* snip */ public: void ageTest(){ int age = ClassImTesting.getAge(); // simple asserts CPPUNIT_ASSERT(age == 18); CPPUNIT_ASSERT_MESSAGE("Must be 18", age == 18); // asserting equality: CPPUNIT_ASSERT_EQUAL(age, 18); CPPUNIT_ASSERT_EQUAL_MESSAGE("Must be 18", age, 18); CPPUNIT_ASSERT_DOUBLES_EQUAL(age * 1.0, 18.0, 1e-10); // exception asserts: CPPUNIT_ASSERT_THROW( ClassImTesting->testAge(age - 1), WrongAgeException); CPPUNIT_ASSERT_NO_THROW( ClassImTesting->testAge(age), WrongAgeException); // inverse asserts: if(age != 18) CPPUNIT_FAIL("Must be 18"); CPPUNIT_ASSERT_ASSERTION_FAIL( CPP_UNIT_ASSERT( age != 18 )); } void setUp(){...} // used to set up the require preconditions void tearDown(){...} // called after tests are run, in order to clean up. };As you can see, the macros provided give a variety of ways to test the code, including checking for boolean true/false, equality with optional epsilon, checking error handling, and manually failing or inverting an assertion. Each macro expands into a cppUnit assertion which includes a message (which you may provide in xx_MESSAGE macros) to help you find the test if it fails, as well as the line in the source from which it originates. There are also two functions, setUp and tearDown, where you should put any logic that must be executed before or after the tests are run, respectively. In addition it is simple to create your own assertions, including custom macros. Their creation is beyond the scope of this introduction, but a clear example is available here. Declaration of intent: The benefit to using a TestFixture comes when telling the rest of your code where your tests lie. Again, through the use of macros, cppUnit will automatically put all of your tests together in a testing suite, available statically. Use is self-explanatory, for example: #include <cppunit/TestCase.h> #include <cppunit/extensions/HelperMacros.h> class suiteOfTests : public CppUnit::TestFixture { // generation macros, using the class and method names CPPUNIT_TEST_SUITE( suiteOfTests ); // use CPPUNIT_TEST_SUB_SUITE for subclasses, // to call inherited tests CPPUNIT_TEST( ageTest ); // add each method name in a CPPUNIT_TEST call CPPUNIT_TEST( heightTest ); // " " CPPUNIT_TEST_SUITE_END(); // generates the TestSuite* suite() method public: void ageTest(){...} void heightTest(){...} /* snip */ };The result of these will be an additional two methods: static void addTestsToSuite(...), which will be called by a tester to register all the methods found inside a CPPUNIT_TEST macro. static CPPUNIT_NS::TestSuite *suite(), which returns a suite of tests that can be executed at runtime. Final preparation:
#include <fstream> #include <cppunit/TestCase.h> #include <cppunit/XmlOutputter.h> #include <cppunit/ui/text/TestRunner.h> #include <cppunit/extensions/TestFactoryRegistry.h> // ... CPPUNIT_TEST_SUITE_REGISTRATION( suiteOfTests ); // ... CppUnit::TestRunner runner; // creates a test executor // Specify XML output and inform the test runner of this format (optional) CppUnit::XmlOutputter* outputter = new CppUnit::XmlOutputter(&runner.result(), std::ofstream("result.xml")); runner.setOutputter(outputter); // use the suite factory, then execute all tests runner.addTest( CppUnit::TestFactoryRegistry::getRegistry().makeTest() ); runner.run( "", false );All units go: Once you have written your cppUnit code, the following should compile it using gcc, as long as the initial build step was successful. This assumes the main() method is in cppTester.cpp, and you want the executable to be called textExec (though the names are easily changed): g++ $(cflags) -o testExec cppTester.cpp ..[any other .cpp / .o].. $(lflags)where $(cflags) are the required compiler flags, as found by running ./cppunit-config --cflags and $(lflags) are the required librarys to be linked, found with ./cppunit-config --link Debriefing: Hopefully this introduction has introduced enough of cppUnit for you to start writing and running your own suite of tests. However, cppUnit has many more features and options for you to explore if you wish. Some places to start include:
|
|