Click here to Skip to main content
13,346,966 members (72,769 online)
Click here to Skip to main content
Add your own
alternative version


26 bookmarked
Posted 14 Jun 2006

Unit--, a simple and easy-to-use unit test aid for C++

, 14 Jun 2006
Rate this:
Please Sign up or sign in to vote.
An article describing a portable unit test framework for C++.

unit-- logo, thank bob for designing



Unit-- is a light-weight unit test framework for C++. It provides the necessary features to help us build portable unit tests easily:

  • declare and register test case at once
  • test suite support
  • simple (only one header and one source file)
  • assertion for bool values, equality, and closeness
  • exception handling
  • need no RTTI
  • integration with IDEs to support TDD

Using the code

Creating a test case

There are three basic macros, namely testSuite, testCase, and assertTrue. They are used to build test cases, and the cases will register themselves to the unit-- framework. Here are the basic steps:

<PRE lang=c++>// 1. include the header file #include "unit--.h" // 2. define your own test suites to organize test cases testSuite(MySuite); // 3. define test cases, and attach them to some suite testCase(CompareCase, MySuite) // 4. write your test code { int x = 1; int y = x + 2; assertTrue(x < y); }

More utilities

The closeValue() function could be used to test the closeness between floating point values. It resides in the namespace unit_minus.

<PRE lang=c++>testCase(Closeness, MySuite) { // expose the namespace using namespace unit_minus; double a = 0.73; double b = 2.19; // test if the 2nd parameter is close enough to the 1st // with precision specified by the 3rd parameter assertTrue(closeValue(b, a * 4, 0.001)); }

If the values are not close enough, we get a simple message reading:

C:\unitmm\haha.cpp(24) : error: 
      Assertion failed: <closeValue(b, a * 4, 0.001)>

It would be better if the exact values could be printed with the message. Simply add an "Info" suffix to achieve it:

assertTrue(closeValueInfo(b, a * 4, 0.001));
C:\unitmm\haha.cpp(24) : error: expected <2.19>, 
        but was <2.92>, not close enough with precision <0.001>

To test equality, there are similar equalValue() and equalValueInfo() functions, also residing in the namespace unit_minus.

Exception handling

Unit-- provides an assertNoArrive() macro for us to deal with exception related tests.

<PRE lang=c++>testCase(ExceptionCase, MySuite) { // check if an exception is thrown as expected try { throw "going to catch clause"; // if an exception is thrown, the code // following it should not be executed assertNoArrive("exception not thrown"); } // try to catch the exact type. // if the exception is not of this type, unit-- would catch it // do NOT use catch(...), or unit-- will miss the failure catch (const char*) { } }

Integration with IDEs

Integrating with IDEs could be helpful for Test Driven Development (TDD). Imagine you are coding with some IDE. The "Compile" button would probably be pressed from time to time. If it announces an error (even a warning for some seasoned developers), you just click the reporting line, and the IDE will lead you to the corresponding source line.

That's what we want in TDD. You write code, and press the Compile button from time to time. Because you write the test before the code, there should be some assertion failure report before you finish. And you just click the reporting line to check what happened, and the IDE leads you to the corresponding assertion in some test case immediately.

To achieve that, the IDE should do the following, every time the project is being built:

  1. Build an executable for the "unit test program", which contains all the test cases
  2. Run the executable before the project itself is built

Let's check an example:

Suppose there's a simple project which has only one function, which should return x powered by 3.

<PRE lang=c++>int cubic(int x);

The project's directory structure looks like this:

+- unitmm_demo
   +- src
        +- cubic.h
        +- cubic.cpp
   +- test
        +- test_cubic.cpp
        +- unit--.h
        +- unit--.cpp

Among all the files, cubic.h and cubic.cpp contains the definition of the function cubic(), test_cubic.cpp contains the unit test case, and unit--.h and unit--.cpp contain the unit-- framework.

For illustration purposes, cubic.cpp contains an apparently incorrect implementation:

<PRE lang=c++>#include "cubic.h" int cubic(int x) { return x; }

The unit test program should run as a step of the building process. The configuration depends on what platform and IDE you are working with. The author chose two of the main-stream platform/IDEs to make a demonstration:

Unix/Linux with g++ and Emacs

The example uses g++ (3.0 or above), GNU make, and GNU Emacs as the IDE.

First, write unitmm_demo/test/makefile for the unit test. Please pay attention to "all", the unit test program will be launched automatically by make.

<PRE lang=c++># makefile for unit test CXX=g++ CXXFLAGS=-Wall -O2 # compile flags OBJS= unit--.o ../src/cubic.o test_cubic.o # link with unit--.cpp RUNNER=a.exe # executable file for unit test # compile command line .cpp.o: ${CXX} -c -o $@ ${CXXFLAGS} $< .PHONY: all clean all: ${RUNNER} ./${RUNNER} format"../test/_f:_l: _m" ${RUNNER}: ${OBJS} ${CXX} ${CXXFLAGS} -o$@ ${OBJS} clean: rm -f ${RUNNER} ${OBJS}

The unit test program has a single command line argument beginning with "format", which specifies the format of the assertion failure report. "_f" will be replaced by the corresponding source file name, "_l" (lower case L) by the line number, and "_m" by the reporting message.

The unitmm_demo/src/makefile is for the project itself. Once again, please look at "all". The unit test program will be launched every time you build the project.

<PRE lang=c++># makefile for the project CXX=g++ CXXFLAGS=-Wall -O2 # compile flags OBJS=cubic.o .cpp.o: ${CXX} -c -o $@ ${CXXFLAGS} $< .PHONY: all clean all: ${OBJS} cd ../test && make all # invoke unit test clean: rm -f ${OBJS} cd ../test && make clean

Finally, open GNU Emacs, find cubic.cpp, and type <M-x> compile <Ret> to launch make. Hurray, the assertion failure is reported in the *compilation* buffer! Press <Ret> on the reporting line, Emacs will lead you to the failed assertion. Here is a screenshot:

screen shot of unit-- with emacs

Windows with VC++

We will use Microsoft Visual C++ 6 as an example here.

First, there need to be a Win32 Console Application project containing all the five source code files.

Then, do the following steps:

  1. Choose Project --> Settings... --> Settings for Win32 Debug.
  2. Find the "Executable for debug session" in the "Debug" tab, and copy the full path of the executable file.
  3. Go to "Post-build step" tab, create a new command, and paste the full path with lower case "vc" as the command line parameter. E.g.: ".\Debug\my_test_prj.exe vc".
  4. Do step 2 and 3 for Win32 Release.
  5. Click the OK button.

Select Build --> Rebuild All from the main menu, and you will get an error. It's not a compile time error. Actually, it is an assertion failure, but double clicking on the reporting line will lead you to the corresponding failed assertion, just like a compile time error.

You can "File --> New" another project in the same workspace, for the real task you are working on, and set the new project to depend on the test project with "Project --> Dependencies". Thus, the unit test program will run whenever you build the "real project".


Unit-- is a simple and easy-to-use unit test framework for C++. Integrating it with the IDE could help you apply Test Driven Development to your projects.


  • 2006-06-13 - initial version.


This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


About the Author

Web Developer
China China
No Biography provided

You may also be interested in...


Comments and Discussions

-- There are no messages in this forum --
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.180111.1 | Last Updated 14 Jun 2006
Article Copyright 2006 by birdiez
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid