1. Home
  2. Tutorials
  3. C/C++
  4. CppUnit
Yolinux.com Tutorial

CppUnit: C++ unit test framework

C++ class unit test framework examples and integration techniques for Jenkins.

CppUnit Description:

The CppUnit test framework is for unit test of C++ class functions. It relies on the hierarchy of a test suite comprising of unit test cases which test class functions. The test begins with setUp() followed by the test and ending with tearDown().

Each unit test employs the use of C++ assert() to test the function results.

C++ assert prototype: void assert (int expression);

If this expression evaluates to 0, this causes an assertion failure that terminates the program.

The assert function will abort the application if false.

Turn assert off: #define NDEBUG
at the beginning of its code, before the inclusion of assert.h

Also see the YoLinux Tutorial on Google C++ unit test.

Man page:
  • assert - abort the program if assertion is false

Installation:

Available as Linux RPMs:
  • cppunit-1.12.0-3.el5.rf
  • cppunit-devel-1.12.0-3.el5.rf
Docs installed to: /usr/share/doc/doc/cppunit-devel-1.12.0/index.html

Debian/Ubuntu: apt-get install libcppunit-doc libcppunit-dev

CppUnit Home Page

CppUnit Example:

C++ class to unit test:

File: CBasicMath.hpp
01#ifndef BASIC_MATH_HPP__
02#define BASIC_MATH_HPP__
03 
04class CBasicMath
05{
06public:
07   int Addition(int x, int y);
08   int Multiply(int x, int y);
09};
10 
11#endif

File: CBasicMath.cpp
01#include "CBasicMath.hpp"
02 
03int CBasicMath::Addition(int x, int y)
04{
05   return (x + y);
06}
07 
08int CBasicMath::Multiply(int x, int y)
09{
10   return (x * y);
11}

CppUnit test driver program:

File: TestBasicMath.cpp
001#include <iostream>
002#include <string>
003#include <list>
004#include <cppunit/TestCase.h>
005#include <cppunit/TestFixture.h>
006#include <cppunit/ui/text/TextTestRunner.h>
007#include <cppunit/extensions/HelperMacros.h>
008#include <cppunit/extensions/TestFactoryRegistry.h>
009#include <cppunit/TestResult.h>
010#include <cppunit/TestResultCollector.h>
011#include <cppunit/TestRunner.h>
012#include <cppunit/BriefTestProgressListener.h>
013#include <cppunit/CompilerOutputter.h>
014#include <cppunit/XmlOutputter.h>
015#include <netinet/in.h>
016 
017#include "CBasicMath.hpp"
018 
019using namespace CppUnit;
020using namespace std;
021 
022//-----------------------------------------------------------------------------
023 
024class TestBasicMath : public CppUnit::TestFixture
025{
026    CPPUNIT_TEST_SUITE(TestBasicMath);
027    CPPUNIT_TEST(testAddition);
028    CPPUNIT_TEST(testMultiply);
029    CPPUNIT_TEST_SUITE_END();
030 
031public:
032    void setUp(void);
033    void tearDown(void);
034 
035protected:
036    void testAddition(void);
037    void testMultiply(void);
038 
039private:
040 
041    CBasicMath *mTestObj;
042};
043 
044//-----------------------------------------------------------------------------
045 
046void
047TestBasicMath::testAddition(void)
048{
049    CPPUNIT_ASSERT(5 == mTestObj->Addition(2,3));
050}
051 
052void
053TestBasicMath::testMultiply(void)
054{
055    CPPUNIT_ASSERT(6 == mTestObj->Multiply(2,3));
056}
057 
058void TestBasicMath::setUp(void)
059{
060    mTestObj = new CBasicMath();
061}
062 
063void TestBasicMath::tearDown(void)
064{
065    delete mTestObj;
066}
067 
068//-----------------------------------------------------------------------------
069 
070CPPUNIT_TEST_SUITE_REGISTRATION( TestBasicMath );
071 
072int main(int argc, char* argv[])
073{
074    // informs test-listener about testresults
075    CPPUNIT_NS::TestResult testresult;
076 
077    // register listener for collecting the test-results
078    CPPUNIT_NS::TestResultCollector collectedresults;
079    testresult.addListener (&collectedresults);
080 
081    // register listener for per-test progress output
082    CPPUNIT_NS::BriefTestProgressListener progress;
083    testresult.addListener (&progress);
084 
085    // insert test-suite at test-runner by registry
086    CPPUNIT_NS::TestRunner testrunner;
087    testrunner.addTest (CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest ());
088    testrunner.run(testresult);
089 
090    // output results in compiler-format
091    CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults, std::cerr);
092    compileroutputter.write ();
093 
094    // Output XML for Jenkins CPPunit plugin
095    ofstream xmlFileOut("cppTestBasicMathResults.xml");
096    XmlOutputter xmlOut(&collectedresults, xmlFileOut);
097    xmlOut.write();
098 
099    // return 0 if tests were successful
100    return collectedresults.wasSuccessful() ? 0 : 1;
101}
Note the use of XmlOutputter for XML output of results

Compile: g++ -o testBasicMath CBasicMath.cpp TestBasicMath.cpp -lcppunit

File: Makefile
01CXX = g++
02INCLUDES= -I./
03CXXFLAGS = -g $(INCLUDES)
04SRCM= ../CBasicMath.cpp
05OBJM = $(SRCM:.cpp=.o)
06LINKFLAGS= -lcppunit
07 
08testbasicmath: TestBasicMath.cpp $(OBJM)
09    $(CXX) $(CXXFLAGS) -o $@ TestBasicMath.cpp $(OBJM) $(LINKFLAGS) $(LINKFLAGSLOG4) $(LIBLOG)
10 
11# Default compile
12 
13.cpp.o:
14    $(CXX) $(CXXFLAGS) -c $< -o $@

Run test: ./testBasicMath

TestBasicMath::testAddition : OK
TestBasicMath::testMultiply : OK

This generates the XML file: cppTestBasicMathResults.xml
01<?xml version="1.0" encoding='ISO-8859-1' standalone='yes' ?>
02<TestRun>
03  <FailedTests></FailedTests>
04  <SuccessfulTests>
05    <Test id="1">
06      <Name>TestBasicMath::testAddition</Name>
07    </Test>
08    <Test id="2">
09      <Name>TestBasicMath::testMultiply</Name>
10    </Test>
11  </SuccessfulTests>
12  <Statistics>
13    <Tests>2</Tests>
14    <FailuresTotal>0</FailuresTotal>
15    <Errors>0</Errors>
16    <Failures>0</Failures>
17  </Statistics>
18</TestRun>

Integration with Jenkins:

Note that I had no luck with the CppUnit plugin for Jenkins and integration required explicit translation of XML unit test results to JUnit format for use by Jenkins.

Ant script to execute Makefile:

File: build.xml
01<property name="make.cmd" value="/usr/bin/make"/>
02 
03...
04...
05...
06 
07<target name="testBasicMathCompile"
08      description="cppunit test compile" >
09  <exec dir="${build.native}/Test" executable="${make.cmd}" failonerror="true">
10 
11  <arg value="testbasicmath"/>
12  </exec>
13</target>
14 
15<target name="testbasicmath"
16      description="cppunit test run" >
17  <exec dir="${build.native}/Test" executable="./testbasicmath" failonerror="false">
18  </exec>
19 
20</target>


The XML results of CppUnit require translation to JUnit style XML for interpretation by Jenkins.

Requires XML conversion from CPP Unit to JUnit using XSLT: cpp2junit.xslt

File: cpp2junit.xslt
01<?xml version="1.0" encoding="UTF-8"?>
02<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
03    <xsl:output method="xml" indent="yes"/>
04    <xsl:template match="/">
05        <testsuite>
06            <xsl:attribute name="errors"><xsl:value-of select="TestRun/Statistics/Errors"/></xsl:attribute>
07            <xsl:attribute name="failures">
08                <xsl:value-of select="TestRun/Statistics/Failures"/>
09            </xsl:attribute>
10            <xsl:attribute name="tests">
11                <xsl:value-of select="TestRun/Statistics/Tests"/>
12            </xsl:attribute>
13            <xsl:attribute name="name">from cppunit</xsl:attribute>
14            <xsl:apply-templates/>
15        </testsuite>
16    </xsl:template>
17    <xsl:template match="/TestRun/SuccessfulTests/Test">
18        <testcase>
19            <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
20            <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
21        </testcase>
22    </xsl:template>
23    <xsl:template match="/TestRun/FailedTests/FailedTest">
24        <testcase>
25            <xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
26            <xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
27            <error>
28                <xsl:attribute name="message">
29                    <xsl:value-of select=" normalize-space(Message)"/>
30                </xsl:attribute>
31                <xsl:attribute name="type">
32                    <xsl:value-of select="FailureType"/>
33                </xsl:attribute>
34                <xsl:value-of select="Message"/>
35                File:<xsl:value-of select="Location/File"/>
36                Line:<xsl:value-of select="Location/Line"/>
37            </error>
38        </testcase>
39    </xsl:template>
40    <xsl:template match="text()|@*"/>
41</xsl:stylesheet>

Use the Gnome program "xsltproc" to apply XSLT to the CppUnit output XML.

Command: xsltproc -o junitTestBasicMathResults.xml cpp2junit.xslt cppTestBasicMathResults.xml

Translated results: junitTestBasicMathResults.xml
1<?xml version="1.0"?>
2<testsuite errors="0" failures="0" tests="2" name="from cppunit">
3  <testcase classname="TestBasicMath" name="testAddition"/>
4  <testcase classname="TestBasicMath" name="testMultiply"/>
5</testsuite>

Ant script for results translation:

File: build.xml
01<property name="xsltproc.cmd" value="/usr/bin/xsltproc"/>
02 
03...
04...
05...
06 
07<target name="testdbCpp2junit"
08      description="Convert cppunit test results to junit test results" >
09  <echo>Tests run from  directory: ${build.native}/Test</echo>
10  <exec dir="${build.native}/Test" executable="${xsltproc.cmd}" failonerror="true">
11  <arg value="-o"/>
12 
13  <arg value="test/data/junitTestBasicMathResults.xml"/>
14  <arg value="cpp2junit.xslt"/>
15  <arg value="cppTestBasicMathResults.xml"/>
16  </exec>
17</target>

xsltproc man page - command line XSLT processor


Jenkins configuration to display JUnit results:
Jenkins/Hudson JUnit configuration
Configuration

For more, see the YoLinux.com Jenkins tutorial

Books:

C++ How to Program
by Harvey M. Deitel, Paul J. Deitel
ISBN #0131857576, Prentice Hall

Fifth edition. The first edition of this book (and Professor Sheely at UTA) taught me to program C++. It is complete and covers all the nuances of the C++ language. It also has good code examples. Good for both learning and reference.

Amazon.com
Exceptional C++: 47 Engineering Puzzles, Programming Problems and Solutions
by Herb Sutter
ISBN #0201615622, Addison-Wesley Professional

Advanced C++ features and STL.

Amazon.com
More Exceptional C++
by Herb Sutter
ISBN #020170434X, Addison-Wesley Professional

Amazon.com
Effective C++: 50 Specific Ways to Improve Your Programs and Design (2nd Edition)
by Scott Meyers
ISBN #0201924889, Addison-Wesley Professional

Amazon.com
More Effective C++: 35 New Ways to improve your Programs and Designs
by Scott Meyers
ISBN #020163371X, Addison-Wesley Professional

Amazon.com