active: Jul 2005 to Mar 2008 download: sf.net/projects/quicktest api: link

QuickTest

Simple C++ Unit Testing

QuickTest is a simple C++ unit testing framework contained in a single header file. Writing a test is easy:

QT_TEST(testSqr)
{
  QT_CHECK_EQUAL(4 * 4, 16);
}

Below are some basic usage instructions, examples, and tips.

Also see QuickProf (performance profiling) and QuickMP (loop parallelization).

Basic Usage

Step 1: Include quicktest.h in your test code.

#include <quicktest/quicktest.h>

Step 2: Write unit tests with the QT_TEST macro.

QT_TEST(myTest)
{
  float x = 12;
  QT_CHECK_CLOSE(x * x, 144, 0.0001);
}

Step 3: Run your tests with the QT_RUN_TESTS macro.

#include <quicktest/quicktest.h>
int main(int argc, char* argv[])
{
  QT_RUN_TESTS;
  return 0;
}

Success & Failure

If, for example, we have 30 unit tests which all pass, we get the following output when the tests are run:

[-------------- RUNNING UNIT TESTS --------------]
Results: 30 succeeded, 0 failed
[-------------- UNIT TESTS FINISHED -------------]

However, if one of our tests fails, like this:

QT_TEST(testSqr)
{
  QT_CHECK_EQUAL(4 * 4, 20);
}

...we get the following output when the tests are run:

[-------------- RUNNING UNIT TESTS --------------]
main.cpp(5): 'testSqr' FAILED: value1(16) should equal value2(20)
Results: 29 succeeded, 1 failed
[-------------- UNIT TESTS FINISHED -------------]

The test failure message contains the test's file name, the line number of the failed assertion, the test's name, and the values passed to the assertion.

(Note to Visual Studio users: it is possible to double-click on failure messages in the output window to jump straight to the failed test code. See "Running Tests Automatically" below.)

Example 1

This test checks whether a ship object's throttle causes it to move.

QT_TEST(testShipThrusters)
{
  Ship s;
  Point start(10, 15, -30);
  s.setPosition(start);
  s.setThrottle(100);
  s.update(12.0); // Accelerate for 12 seconds.
  Point end = s.getPosition();
  QT_CHECK_GREATER(distance(start, end), 5);
}

Example 2

These tests demonstrate the use of a "fixture" (a piece of reusable code that can be used in multiple tests). The first test checks whether the ship's initial position is set correctly. The second one tests the ship's reverse throttle capability; it accelerates the ship forward for some time, stops it, accelerates it backward the same amount of time, then checks whether it ends up in the starting position.

struct ShipFixture
{
  ShipFixture()
  {
    // Setup here.
    start.set(10, 15, -30);
    ship.setPosition(start);
    ship.setThrottle(100);
  }

  ~ShipFixture()
  {
    // Teardown here.
  }

  Ship ship;
  Point start;
};

QT_TEST(testShipStartPosition)
{
  ShipFixture f;
  Point pos = f.ship.getPosition();
  QT_CHECK_CLOSE(distance(f.start, pos), 0, 0.001);
}

QT_TEST(testShipReverseThrottle)
{
  ShipFixture f;
  f.ship.update(12.0); // Accelerate 12 seconds.
  f.ship.setVelocity(0); // Stop the ship.
  f.ship.setThrottle(-100);
  f.ship.update(12.0); // Accelerate backward.
  Point end = f.ship.getPosition();
  QT_CHECK_CLOSE(distance(f.start, end), 0, 0.001);
}

Running Tests Automatically

It is usually best to run your tests immediately after each build of the code being unit tested. This can be automated in most build systems, including Visual Studio, Make, and SCons. You will probably want a separate executable that contains only the unit tests. For example, you could use a simple main.cpp test runner like this:

#include <quicktest/quicktest.h>
int main(int argc, char* argv[])
{
  QT_RUN_TESTS;
  return 0;
}

Then compile main.cpp, along with your unit test .cpp files, into a test runner executable. (Each of these .cpp files should include quicktest.h.) Each time you build your main code, make sure this executable is updated too.

Say your test executable is called myUnitTests.exe. In Make or SCons, you can add a rule to run myUnitTests.exe immediately after building your main code. In Visual Studio version 7.0, add something like .\Debug\myUnitTests.exe or .\$(OutDir)\$(TargetFileName) to Build Events => Post-Build Event => Command Line under the project properties for your main code. Now the test runner executable will run after each build.

Note to Visual Studio users: running the tests as a Post-Build Event sends the QuickTest output to the Visual Studio output window (assuming you left the QuickTest output stream as standard output). The test failure messages are formatted in a way that Visual Studio can parse, so you can simply double-click on a failure message to jump straight to the failed test code. (This only seems to work reliably in release mode where the C++ __FILE__ macro expands to the relative file name; in debug mode __FILE__ expands to the absolute file name which might be truncated.)