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.

Tags: , , , , ,

8 Responses to “Improving QtTest usability with QtTestUtil”

  1. Shanker says:

    This is awesome! I can’t wait to get home and test this out — thanks for saving me the time to do this myself.

  2. kunal says:

    i was looking for someting like this. this will be great help.

  3. Pablo says:

    Is possible create a automated test using QtTest?
    For example ….write in LineEdit , change icons. clickmouse.
    Good example.
    Thanks!!

  4. Awesome, I love it. Great that you have done this. Do you thought about a UI where you can decide which tests to run ?

  5. Bhuvnesh says:

    Owsome remko it is really very generic test tool, Keep writing beautiful utils.

  6. Hogwarts says:

    I’m using this util but I can’t create a widget and test it…someone know why??

    this is my code:

    class MyFirstClassTest : public QObject
    {
    Q_OBJECT

    private slots:
    void initTestCase() {
    }

    void cleanupTestCase() {
    }

    void testMyMethod() {
    CustomSlider* slider;
    slider = new CustomSlider(NULL);
    slider->setSpacing(8);
    QCOMPARE(slider->spacing(), 8);
    }
    };

    and this is the error:

    ********* Start testing of MyFirstClassTest *********
    Config: Using QTest library 4.5.2, Qt 4.5.2
    PASS : MyFirstClassTest::initTestCase()
    QFATAL : MyFirstClassTest::testMyMethod() QWidget: Cannot create a QWidget when no GUI is being used
    FAIL! : MyFirstClassTest::testMyMethod() Received a fatal error.
    Loc: [Unknown file(0)]
    Totals: 1 passed, 1 failed, 0 skipped
    ********* Finished testing of MyFirstClassTest *********

  7. @Hogwarts If you have widgets in your test, Qt requires you to have a QApplication instantiated in your test application. Modify SimpleTestUtil.cpp, and change the QCoreApplication to QApplication. Maybe you need to do a app.run() at the end too.

    However, having widgets in unit tests is typically a bad smell. There should be no logic in your GUI widgets, so testing them shouldn’t make sense. GUI objects typically need user interaction, which is not something you can automate (and which may get you in trouble with the Qt event loop too). Try to pull all the non-GUI stuff out of your widget.

Leave a Reply