Unit Testing and Code Coverage For C++
Unit Testing and Code Coverage For C++
1
cppUnit
2
Code in an individual test
Use assertion macros defined in cppunit
If assertion fails, an exception is thrown
CPPUNIT_ASSERT(condition):
Checks the condition and throws an exception if it's false.
CPPUNIT_ASSERT_MESSAGE(message, condition):
Checks the condition and throws an exception and showing specified message if
it is false.
CPPUNIT_ASSERT_EQUAL(expected,current):
Checks whether the expected condition is the same as current, and raises an
exception showing the expected and current values.
CPPUNIT_ASSERT_EQUAL_MESSAGE(message,expected,c
urrent)
Checks whether the expected is the same as the actual, and raises an exception
showing the expected and current values, and specified message.
CPPUNIT_ASSERT_DOUBLES_EQUAL(expected,current,delta):
Checks whether the expected and current difference is smaller than delta. If it 3
fails, the expected and current values are shown.
TestFixture
Each test should be derived from the abstract
class TestFixture
Override two functions:
setUp
operations that would be invoked prior to each individual test,
e.g. create new clean instances of class ready for next test
tearDown
operations that would be invoked after to each individual test,
e.g. deletes instances
4
TestSuite, TestRunner
TestSuite
Groups a number of tests (using TestFixture) so
that they can all be run
TestRunner
Driver program
5
Test driven development
Test twice, code once
“The style here is to write a few lines of
code, then a test that should run, or even
better, to write a test that won't run, then
write the code that will make it run.”
6
Test driven development – step 0
Define class Bitmap
Owns an array of unsigned long integers
Methods
boolean Identity(const Bitmap& other)
Are we the same Bitmap
Compare our address with other’s address!
boolean Equals(const Bitmap& other)
Are we equal?
What do you mean equal?
• This is the part we test twice – code once!
void Zero()
Set my bits all to zero.
7
#ifndef __MYBITSCLASS__
#define __MYBITSCLASS__
Class Bitmap
// Code assumes 32-bit unsigned long integers
#define MAXBITS 512
#define NUMWORDS 16
typedef unsigned long Bits;
class Bitmap {
public:
Bitmap();
void Zero(void);
bool Equals(const Bitmap &other) const;
bool Identity(const Bitmap &other) const;
private:
Bits fBits[NUMWORDS];
};
#endif
8
#include "Bitmap.h"
Bitmap::Bitmap() Class Bitmap
{
Zero();
}
void Bitmap::Zero(void)
{
for(int i=0;i<NUMWORDS; i++)
fBits[i] = 0;
}
bool Bitmap::Identity(const Bitmap& other) const
{
return (this == &other);
}
bool Bitmap::Equals(const Bitmap& other) const
{
return Identity(other);
// Incorrect implementation
}
9
Now write a test for Bitmap -- TestFixture
#ifndef BITMAPTEST_H
#define BITMAPTEST_H
#include <cppunit/TestCase.h>
#include <cppunit/extensions/HelperMacros.h>
#include "Bitmap.h"
#endif 10
#include "BitmapTest.h"
#include "Bitmap.h"
CPPUNIT_TEST_SUITE_REGISTRATION (BitmapTest);
void BitmapTest::setUp()
{
// Put the bitmaps back in standard state
// (Need at least two as doing things like
// checking equality)
bitmap1.Zero();
bitmap2.Zero();
}
void BitmapTest::tearDown()
{
// Nothing to do
}
11
void BitmapTest::testEquals()
{
// Identity should work
CPPUNIT_ASSERT(bitmap1.Identity(bitmap1));
CPPUNIT_ASSERT(bitmap2.Identity(bitmap2));
CPPUNIT_ASSERT(!bitmap1.Identity(bitmap2));
// so should this
CPPUNIT_ASSERT(bitmap2.Equals(bitmap2));
12
The Driver -- TestRunner
// Reporting
CPPUNIT_NS :: CompilerOutputter compileroutputter (&collectedresults, std::cerr);
compileroutputter.write ();
return collectedresults.wasSuccessful () ? 0 : 1; 13
}
Build and run
!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0
14
“Refactor”
15
Next increment – more functionality in
Bitmap
class Bitmap {
public:
Bitmap();
void Zero(void);
void SetBit(int bitnum);
int Count(void) const;
16
BitmapTest
class BitmapTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE (BitmapTest);
CPPUNIT_TEST (testEquals);
CPPUNIT_TEST (testSetBit);
CPPUNIT_TEST (testSetBitAndCount);
CPPUNIT_TEST_SUITE_END ();
private:
Bitmap bitmap1;
Bitmap bitmap2;
public:
void setUp();
void tearDown();
protected:
void testEquals();
void testSetBit();
void testSetBitAndCount();
};
17
BitmapTest
18
void BitmapTest::testEquals()
{ BitmapTest
// Identity should work
CPPUNIT_ASSERT(bitmap1.Identity(bitmap1));
CPPUNIT_ASSERT(bitmap2.Identity(bitmap2));
CPPUNIT_ASSERT(!bitmap1.Identity(bitmap2));
CPPUNIT_ASSERT(bitmap1.Equals(bitmap1));
CPPUNIT_ASSERT(bitmap2.Equals(bitmap2));
CPPUNIT_ASSERT(bitmap1.Equals(bitmap2));
20
void BitmapTest::testSetBitAndCount()
{ BitmapTest
// Set some bits and check that count equals number of bits set
int bits1[] = { 0, 3, 17, 21, 33, 54, 68, 77, 91, 103, 211, 304 };
int bits2[] = { 0, 31, 32, 33, 63, 64, 65, 300, 400, 500, 511 };
int count1 = sizeof(bits1)/sizeof(int);
int count2 = sizeof(bits2)/sizeof(int);
for(int i=0;i<count1;i++)
bitmap1.SetBit(bits1[i]);
for(int i=0;i<count2;i++)
bitmap2.SetBit(bits2[i]);
CPPUNIT_ASSERT_EQUAL(count1, bitmap1.Count());
// Deliberate error to get a failed test
CPPUNIT_ASSERT_EQUAL(count1, bitmap2.Count());
}
21
Rebuild, rerun
!!!FAILURES!!! Text
Test Results:
Run: 3 Failures: 1 Errors: 0
Available at
http://sourceforge.net/projects/cppunit
23
Tutorials …
http://www.comp.nus.edu.sg/~cs3214s/too
ls/cppunitSol.html
http://www.evocomp.de/tutorials/tutorium_
cppunit/howto_tutorial_cppunit_en.html
Documentation with cppUnit
Docs folder in /share/cs-pub/222/testing
“Money” tutorial
24
Code coverage
g++ compiler and
gcov analysis tool
25
Compilation for code coverage
26
Run, then use gcov to analyze
NetBeans can be used to run the application
under test
Best to run several times with different input data so as
to try to test all options
gcov analysis should be done in terminal
session
cd to directory with C++ source
Identify directory where gcov files (.gcno, .gcda) were
created – should be ./build/Debug/GNU-Linux-x86
Run gcov specifying the data directory and file for
analysis
27
Gcov analysis : function summaries
gcov –o ./build/Debug/GNU-Linux-x86 -f Bitmap.cc
100.00% of 3 source lines executed in function void Bitmap::Zero()
100.00% of 7 source lines executed in function void Bitmap::SetBit(int)
100.00% of 8 source lines executed in function void Bitmap::ClearBit(int)
0.00% of 4 source lines executed in function void Bitmap::SetAs(int, int)
85.71% of 7 source lines executed in function int Bitmap::TestBit(int) const
100.00% of 7 source lines executed in function void Bitmap::FlipBit(int)
100.00% of 2 source lines executed in function void
Bitmap::ReadFrom(std::fstream&)
…
100.00% of 4 source lines executed in function int Bitmap::Equals(const
Bitmap&) const
94.32% of 88 source lines executed in file Bitmap.cc
28
Gcov analysis: branch counts
$ gcov –o ./build/Debug/GNU-Linux-x86 -c Bitmap.cc
…
94.32% of 88 source lines executed in file Bitmap.cc
Creating Bitmap.cc.gcov.
$ cat Bitmap.cc.gcov
#include "Bitmap.h"
Bitmap::Bitmap()
14 {
14 Zero();
}
void Bitmap::Zero(void)
15 {
255 for(int i=0;i<NUMWORDS; i++)
240 fBits[i] = 0;
}
void Bitmap::SetBit(int bitnum)
113 {
113 if((bitnum < 0) || (bitnum >= MAXBITS))
113 return;
113 int word = bitnum / 32;
…
29
Inspect profiles
30