Dan's Tech Den For the Cyber Warrior

19Nov/0917

Using CppUnit with Visual Studio

It is a unit testing framework ( a port of JUnit ) for C++ .
The benifit of having a unit testing procedure is that , you can use it either in Test Driven Development or as a standalone test (for testing when needed).
With CPPunit, its very easy to write and run unit tests, as well as integrate the runs with the build process.

Installing CppUnit

The first thing is, there is no installation. The distribution is the source code which must be compiled with the compiler you are using for your C++ work.

Setting up CPPUnit (on windows using Visual Studio):

  1. Download latest release of CPPUnit
  2. Extract the zip contents.
  3. Open the Visual Studio 6 workspace file in the examples directory of the extracted folder.
  4. If you are using Visual Studio 2005 or 2008, it wont compile out of the box.

Fix For Visual studio 2005 and 2008

Open file MsDevCallerListCtrl.cpp in the folder srcmsvc6testrunner.
Find the following line

#import "libid:80cc9f66-e7d8-4ddd-85b6-d9e6cd0e93e2" version("7.0") lcid("0") raw_interfaces_only named_guids

and change the version("7.0") to:
version("8.0") for VS 2005
version("9.0") for VS 2008

Now do a batch build for all configurations.
Dont worry about errors yet.
Go and look into the lib directory in the cppunit directory.
if you have cppunit.lib, cppunit_dll.lib and cppunit_dll.dll, then you are ready to go.

Adding the include and lib paths to Visual Studio environment
open Tools->Options.
Choose Projects and Solutions -> VC++ Directories

from the dropdown for "Show directories for" choose "Include Files"
and add(by clicking in the blank space on the bottom) -> <cppunit directory>include

for "Library files"
Add-> <cppunit directory>lib

Using it in a project

Read the Cookbook to get an idea how CPPUnit works.

Open the visual studio solution for the project you want to integrate testing into.

The Add a new project to the solution (this will be our testing project).

Open this new project's properties.
in the linker section under input. Add the cppuni.lib or cppunit_dll.lib (depending on you code generation options) to the Additional Dependencies.

For this to work either the .lib files should be in a directory in the include paths (it should be if you followed this entry from the top) or should be included in the project (by add item).

Add a header file ( for reference i'll name it test.h)

Include the header files for classes you want to test from the other project. Like this:

#include "../<project name>/<header file>"

also include the following files

#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
#include <cppunit/TextTestRunner.h>

you may exclude the test runner from here and include it in the cpp file with main function.

make a class that extends the the CppUnit::TestFixture class.

For example:

class g3Test : public CppUnit::TestFixture {
	CPPUNIT_TEST_SUITE( g3Test);
	CPPUNIT_TEST( testRun );
	CPPUNIT_TEST_SUITE_END();
  public:
	void testRun(){
		CPPUNIT_ASSERT_EQUAL(1.2f, greater3(1.2, 0.26, -1.2) );
		CPPUNIT_ASSERT_EQUAL(0.0f, greater3(-3.2, -1, 0) );
		CPPUNIT_ASSERT_EQUAL(3.0f, greater3(2, 3, 2) );
		CPPUNIT_ASSERT_EQUAL(5.1f, greater3(5.1, 5.1, 5.1) );
		CPPUNIT_ASSERT_EQUAL(61.02f, greater3(61.02, 61.02, 1) );
		CPPUNIT_ASSERT_EQUAL(-5.0f, greater3(-26, -10, -5) );
	}
};

the macro CPPUNIT_TEST_SUITE( ); starts the test suite
CPPUNIT_TEST( ); defines which function to run as the test. There can be multiple CPPUNIT_TEST entries.
And the Suite is ended using CPPUNIT_TEST_SUITE_END(); macro.

Apart from the testing functions.
Two more functions can be defined, which are automatically run.
1. void setUp();
2. void tearDown();

as the name suggests. Setup is run at start of test case execution and tearDown at end.
Thus setUp can be used for any sort of initialization and tearDown for any cleanup sfter test completion.

The cpp file where the tests are run

include the following files in the cpp file

#include "test.h"
#include <cppunit/TextTestRunner.h> //(not needed if included in test.h)

Define a main function

int main(int argc, char * argv[])

You can do any processing or output in this function.

To run the tets do the following:

CppUnit::TextTestRunner runnerText;
runnerText.addTest( g3Test::suite() );
runnerText.run();

The above code does the following tasks:
1. create an instance of the testRunner class (you can also use MFC or QT test runner)
2. add tests using the automatic suite creation function of our test class
3. Run tests

The test runner will display the result.

To get the screen to hold you can add getch() at the end.

Thanks for reading.

This was about the basics of CPPUnit. I will post further entries for examples and build automation.

Comments (17) Trackbacks (2)
  1. I see you don’t monetize your site, don’t waste your traffic, you
    can earn extra bucks every month because you’ve got high quality content.

    If you want to know how to make extra bucks, search for: Mrdalekjd methods for $$$

  2. I read this article completely regarding the comparison of newest
    and previous technologies, it’s awesome article.

  3. Well, now that we have our unit tests running, how about integrating unit testing to our build process ?

  4. thanks. it worked out well
    but i’ve been using a simpler ver:
    CPPUNIT_ASSERT_EQUAL(1,1); // PASS

  5. While i click on your Rss it looks as being a whole lot of weird text message, may be the issue on my own aspect?

  6. @Chris
    Chris,
    I am also getting a lot of linker errors. can you pls explain how did you solve this problem. I didnt understand which files did you delete….?

  7. This is a life saver!!! thanx for the effort

  8. Nevermind, I got it.

  9. Or how can I get the actual files and not the CVS files?

  10. Where can I get files without “,v” in the extension?

  11. I deleted my files and restarted, and got it to work.

  12. I added the cppunit*.lib files in my Additional files, and now am getting this…

    1>Linking…
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::basic_string<char,struct std::char_traits,class std::allocator >(char const *)” (??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@PBD@Z) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: char const * __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::c_str(void)const ” (?c_str@?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QBEPBDXZ) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: class std::basic_string<char,struct std::char_traits,class std::allocator > & __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::operator=(char const *)” (??4?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAEAAV01@PBD@Z) already defined in libcpmtd.lib(locale0.obj)
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::~basic_string<char,struct std::char_traits,class std::allocator >(void)” (??1?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@XZ) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::basic_string<char,struct std::char_traits,class std::allocator >::basic_string<char,struct std::char_traits,class std::allocator >(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??0?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@QAE@ABV01@@Z) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::_Container_base_secure::~_Container_base_secure(void)” (??1_Container_base_secure@std@@QAE@XZ) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “void __cdecl std::_Debug_message(wchar_t const *,wchar_t const *,unsigned int)” (?_Debug_message@std@@YAXPB_W0I@Z) already defined in libcpmtd.lib(stdthrow.obj)
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::_Lockit::~_Lockit(void)” (??1_Lockit@std@@QAE@XZ) already defined in libcpmtd.lib(xlock.obj)
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::_Lockit::_Lockit(int)” (??0_Lockit@std@@QAE@H@Z) already defined in libcpmtd.lib(xlock.obj)
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: void __thiscall std::_Container_base_secure::_Orphan_all(void)const ” (?_Orphan_all@_Container_base_secure@std@@QBEXXZ) already defined in HelloTester.obj
    1>msvcprtd.lib(MSVCP90D.dll) : error LNK2005: “public: __thiscall std::_Container_base_secure::_Container_base_secure(void)” (??0_Container_base_secure@std@@QAE@XZ) already defined in HelloTester.obj
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: “public: virtual __thiscall std::exception::~exception(void)” (??1exception@std@@UAE@XZ) already defined in LIBCMTD.lib(stdexcpt.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: “public: __thiscall std::exception::exception(void)” (??0exception@std@@QAE@XZ) already defined in LIBCMTD.lib(stdexcpt.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: “public: __thiscall std::exception::exception(class std::exception const &)” (??0exception@std@@QAE@ABV01@@Z) already defined in LIBCMTD.lib(stdexcpt.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: __invalid_parameter already defined in LIBCMTD.lib(invarg.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: __CrtDbgReportW already defined in LIBCMTD.lib(dbgrptw.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: “public: __thiscall std::exception::exception(char const * const &)” (??0exception@std@@QAE@ABQBD@Z) already defined in LIBCMTD.lib(stdexcpt.obj)
    1>MSVCRTD.lib(MSVCR90D.dll) : error LNK2005: _memmove_s already defined in LIBCMTD.lib(memmove_s.obj)
    1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: “private: __thiscall type_info::type_info(class type_info const &)” (??0type_info@@AAE@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
    1>MSVCRTD.lib(ti_inst.obj) : error LNK2005: “private: class type_info & __thiscall type_info::operator=(class type_info const &)” (??4type_info@@AAEAAV0@ABV0@@Z) already defined in LIBCMTD.lib(typinfo.obj)
    1>LINK : warning LNK4098: defaultlib ‘MSVCRTD’ conflicts with use of other libs; use /NODEFAULTLIB:library
    1>LINK : warning LNK4199: /DELAYLOAD:OleAcc.dll ignored; no imports found from OleAcc.dll

  13. I created a separate solution file for the project that has the test code, instead of adding the project in the solution file for the code I wanted to test. Other than that, I followed all the above instructions, including adding the cppunit…include and …lib dirs in VS2008 -> Tools menu.

    I get the following link errors.

    1>HelloTester.obj : error LNK2019: unresolved external symbol “public: __thiscall CppUnit::SourceLine::SourceLine(class std::basic_string<char,struct std::char_traits,class std::allocator > const &,int)” (??0SourceLine@CppUnit@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@H@Z) referenced in function “public: void __thiscall HelloTester::testRun(void)” (?testRun@HelloTester@@QAEXXZ)
    1>HelloTester.obj : error LNK2019: unresolved external symbol “public: virtual __thiscall CppUnit::SourceLine::~SourceLine(void)” (??1SourceLine@CppUnit@@UAE@XZ) referenced in function “void __cdecl CppUnit::assertEquals(int const &,int const &,class CppUnit::SourceLine,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??$assertEquals@H@CppUnit@@YAXABH0VSourceLine@0@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
    1>HelloTester.obj : error LNK2019: unresolved external symbol “public: static void __cdecl CppUnit::Asserter::failNotEqual(class std::basic_string<char,struct std::char_traits,class std::allocator >,class std::basic_string<char,struct std::char_traits,class std::allocator >,class CppUnit::SourceLine const &,class CppUnit::AdditionalMessage const &,class std::basic_string<char,struct std::char_traits,class std::allocator >)” (?failNotEqual@Asserter@CppUnit@@SAXV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@0ABVSourceLine@2@ABVAdditionalMessage@2@0@Z) referenced in function “void __cdecl CppUnit::assertEquals(int const &,int const &,class CppUnit::SourceLine,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??$assertEquals@H@CppUnit@@YAXABH0VSourceLine@0@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)
    1>HelloTester.obj : error LNK2019: unresolved external symbol “public: __thiscall CppUnit::AdditionalMessage::AdditionalMessage(class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??0AdditionalMessage@CppUnit@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function “void __cdecl CppUnit::assertEquals(int const &,int const &,class CppUnit::SourceLine,class std::basic_string<char,struct std::char_traits,class std::allocator > const &)” (??$assertEquals@H@CppUnit@@YAXABH0VSourceLine@0@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z)

  14. Ignore my comment. I got the *.tar.gz file and unzipped it with 7zip.

  15. The download site you link to has a *.bz2 file, not *.zip. Will the *.bz2 file have the *.zip file?

  16. Wow, I didn’t know about this topic until now. Thanks!!

  17. Lifesaver. Thanks Man.
    Appreciated!
    🙂


Leave a comment