|
Related YoLinux Tutorials:
°Linux and C++
°C++ Unions & Structures
°C++ Templates
°C++ STL
°C++ STL Map
°C++ String Class
°C++ Singleton
°C++ Coding Style
°C++ XML Beans
°C/C++ Dynamic Memory
°C++ Memory Corruption
°C/C++ Signal Handling
°Jenkins CI
°YoLinux Tutorials Index
Free Information Technology Magazines and Document Downloads
|
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
Man page:
- assert - abort the program if assertion is false
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
C++ class to unit test:
File: CBasicMath.hpp
-
#ifndef BASIC_MATH_HPP__
#define BASIC_MATH_HPP__
class CBasicMath
{
public:
int Addition(int x, int y);
int Multiply(int x, int y);
};
#endif
|
File: CBasicMath.cpp
-
#include "CBasicMath.hpp"
int CBasicMath::Addition(int x, int y)
{
return (x + y);
}
int CBasicMath::Multiply(int x, int y)
{
return (x * y);
}
|
CppUnit test driver program:
File: TestBasicMath.cpp
-
#include <iostream>
#include <string>
#include <list>
#include <cppunit/TestCase.h>
#include <cppunit/TestFixture.h>
#include <cppunit/ui/text/TextTestRunner.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/extensions/TestFactoryRegistry.h>
#include <cppunit/TestResult.h>
#include <cppunit/TestResultCollector.h>
#include <cppunit/TestRunner.h>
#include <cppunit/BriefTestProgressListener.h>
#include <cppunit/CompilerOutputter.h>
#include <cppunit/XmlOutputter.h>
#include <netinet/in.h>
#include "CBasicMath.hpp"
using namespace CppUnit;
using namespace std;
//-----------------------------------------------------------------------------
class TestBasicMath : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE(TestBasicMath);
CPPUNIT_TEST(testAddition);
CPPUNIT_TEST(testMultiply);
CPPUNIT_TEST_SUITE_END();
public:
void setUp(void);
void tearDown(void);
protected:
void testAddition(void);
void testMultiply(void);
private:
CBasicMath *mTestObj;
};
//-----------------------------------------------------------------------------
void
TestBasicMath::testAddition(void)
{
CPPUNIT_ASSERT(5 == mTestObj->Addition(2,3));
}
void
TestBasicMath::testMultiply(void)
{
CPPUNIT_ASSERT(6 == mTestObj->Multiply(2,3));
}
void TestBasicMath::setUp(void)
{
mTestObj = new CBasicMath();
}
void TestBasicMath::tearDown(void)
{
delete mTestObj;
}
//-----------------------------------------------------------------------------
CPPUNIT_TEST_SUITE_REGISTRATION( TestBasicMath );
int main(int argc, char* argv[])
{
// informs test-listener about testresults
CPPUNIT_NS::TestResult testresult;
// register listener for collecting the test-results
CPPUNIT_NS::TestResultCollector collectedresults;
testresult.addListener (&collectedresults);
// register listener for per-test progress output
CPPUNIT_NS::BriefTestProgressListener progress;
testresult.addListener (&progress);
// insert test-suite at test-runner by registry
CPPUNIT_NS::TestRunner testrunner;
testrunner.addTest (CPPUNIT_NS::TestFactoryRegistry::getRegistry().makeTest ());
testrunner.run(testresult);
// output results in compiler-format
CPPUNIT_NS::CompilerOutputter compileroutputter(&collectedresults, std::cerr);
compileroutputter.write ();
// Output XML for Jenkins CPPunit plugin
ofstream xmlFileOut("cppTestBasicMathResults.xml");
XmlOutputter xmlOut(&collectedresults, xmlFileOut);
xmlOut.write();
// return 0 if tests were successful
return collectedresults.wasSuccessful() ? 0 : 1;
}
|
Note the use of XmlOutputter for XML output of results
Compile: g++ -o testBasicMath CBasicMath.cpp TestBasicMath.cpp -lcppunit
File: Makefile
-
CXX = g++
INCLUDES= -I./
CXXFLAGS = -g $(INCLUDES)
SRCM= ../CBasicMath.cpp
OBJM = $(SRCM:.cpp=.o)
LINKFLAGS= -lcppunit
testbasicmath: TestBasicMath.cpp $(OBJM)
$(CXX) $(CXXFLAGS) -o $@ TestBasicMath.cpp $(OBJM) $(LINKFLAGS) $(LINKFLAGSLOG4) $(LIBLOG)
# Default compile
.cpp.o:
$(CXX) $(CXXFLAGS) -c $< -o $@
|
Run test: ./testBasicMath
-
TestBasicMath::testAddition : OK
TestBasicMath::testMultiply : OK
This generates the XML file: cppTestBasicMathResults.xml
-
<?xml version="1.0" encoding='ISO-8859-1' standalone='yes' ?>
<TestRun>
<FailedTests></FailedTests>
<SuccessfulTests>
<Test id="1">
<Name>TestBasicMath::testAddition</Name>
</Test>
<Test id="2">
<Name>TestBasicMath::testMultiply</Name>
</Test>
</SuccessfulTests>
<Statistics>
<Tests>2</Tests>
<FailuresTotal>0</FailuresTotal>
<Errors>0</Errors>
<Failures>0</Failures>
</Statistics>
</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
<property name="make.cmd" value="/usr/bin/make"/>
...
...
...
<target name="testBasicMathCompile"
description="cppunit test compile" >
<exec dir="${build.native}/Test" executable="${make.cmd}" failonerror="true">
<arg value="testbasicmath"/>
</exec>
</target>
<target name="testbasicmath"
description="cppunit test run" >
<exec dir="${build.native}/Test" executable="./testbasicmath" failonerror="false">
</exec>
</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
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/">
<testsuite>
<xsl:attribute name="errors"><xsl:value-of select="TestRun/Statistics/Errors"/></xsl:attribute>
<xsl:attribute name="failures">
<xsl:value-of select="TestRun/Statistics/Failures"/>
</xsl:attribute>
<xsl:attribute name="tests">
<xsl:value-of select="TestRun/Statistics/Tests"/>
</xsl:attribute>
<xsl:attribute name="name">from cppunit</xsl:attribute>
<xsl:apply-templates/>
</testsuite>
</xsl:template>
<xsl:template match="/TestRun/SuccessfulTests/Test">
<testcase>
<xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
<xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
</testcase>
</xsl:template>
<xsl:template match="/TestRun/FailedTests/FailedTest">
<testcase>
<xsl:attribute name="classname" ><xsl:value-of select="substring-before(Name, '::')"/></xsl:attribute>
<xsl:attribute name="name"><xsl:value-of select="substring-after(Name, '::')"/></xsl:attribute>
<error>
<xsl:attribute name="message">
<xsl:value-of select=" normalize-space(Message)"/>
</xsl:attribute>
<xsl:attribute name="type">
<xsl:value-of select="FailureType"/>
</xsl:attribute>
<xsl:value-of select="Message"/>
File:<xsl:value-of select="Location/File"/>
Line:<xsl:value-of select="Location/Line"/>
</error>
</testcase>
</xsl:template>
<xsl:template match="text()|@*"/>
</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
-
<?xml version="1.0"?>
<testsuite errors="0" failures="0" tests="2" name="from cppunit">
<testcase classname="TestBasicMath" name="testAddition"/>
<testcase classname="TestBasicMath" name="testMultiply"/>
</testsuite>
|
Ant script for results translation:
-
File: build.xml
<property name="xsltproc.cmd" value="/usr/bin/xsltproc"/>
...
...
...
<target name="testdbCpp2junit"
description="Convert cppunit test results to junit test results" >
<echo>Tests run from directory: ${build.native}/Test</echo>
<exec dir="${build.native}/Test" executable="${xsltproc.cmd}" failonerror="true">
<arg value="-o"/>
<arg value="test/data/junitTestBasicMathResults.xml"/>
<arg value="cpp2junit.xslt"/>
<arg value="cppTestBasicMathResults.xml"/>
</exec>
</target>
|
xsltproc man page - command line XSLT processor
Jenkins configuration to display JUnit results:
-
Configuration
For more, see the YoLinux.com Jenkins tutorial
Books: |
-
|
|