Improving QtTest usability with QtTestUtil

As much as I like CppUnit for writing C++ unit tests, I still prefer using Qt’s built-in QtTest module for Qt-based projects. This avoids a dependency on an external library, lowering the threshold for running and writing unit tests. Unfortunately, QtTest is very basic, and lacks some useful features such as automatic test registration and running multiple test suites in one test binary. In order to improve QtTest’s usability, I started creating some macros and classes that fill in some of the gaps, and bundled them into QtTestUtil.

QtTest’s recommended way to write unit tests is to compile and link one test suite per class separately, and using the QTEST_MAIN macro to generate a main() that runs this particular test suite. However, this introduces quite a bit of overhead in writing (creating a project file for every test/class), building (linking a binary for every test/class), and running (running a separate binary for every test/class, usually using a custom script) all unit tests. This overhead is especially painful in a project with many classes. All this conflicts with the general rule that both creating and running unit tests should be very efficient, and makes QtTest not well suited for unit testing as it is.

A first attempt at solving this problem is by manually creating a main() function that runs all tests. For example:

#include "MyFirstTest.h"
#include "MySecondTest.h"

int main(int argc, char* argv) {
  int result = 0;
  MyFirstTest test1;
  result |= QTest::qExec(&test1, argc, argv);
  MySecondTest test2;
  result |= QTest::qExec(&test2, argc, argv);
  return result;

The resulting binary runs all listed test suites. The downside of this approach is that you have to write quite a bit of boilerplate code: every test binary needs to have its own main() function that explicitly runs all the tests in that test suite, and which needs to be put in a file that has to include all the tests separately. In order remedy this, I took the idea from CppUnit to provide a macro which auto-registers a test suite, and makes it easy to run all registered test suites at once. Creating a test suite is now as simple as creating a .cpp file for every unit test, adding a call to QTTESTUTIL_REGISTER_TEST to that file, and compiling that together with a shared main() that does nothing but call runTests() on the test registry. Since this main() does not explicitly depend on any test, QtTestUtil comes with a SimpleChecker.cpp containing this call, and which can be used by all unit test modules. As a result, no module needs to provide its own main() anymore.

An example of a unit test module using the macro and the shared checker described above can be found in the Example subdir of the QtTestUtil repository. It is worth noticing that these QtTest-based unit tests are more compact than the same unit test written in CppUnit (because the latter requires you to call a macro for every test in a fixture).

This is just a first set of utilities that QtTestUtil provides on top of QtTest. More utility classes and macros will be added as they are needed.

Published by

Remko Tronçon

Software Engineer · Hobby musician · BookWidgets