8.7.  QTestLib

[ fromfile: unittest.xml id: testframework ]

The most common way to write testing code is to organize it in a unit-based framework. Qt 4 introduced the QTestLib framework of helper-macros and test runners to facilitate the writing of unit tests for applications and libraries that use Qt. All public methods in this framework are in the QTest namespace. The next examples use this framework.

A Test Class is a class derived from QObject, with some private slots for one or more test functions. A test case is a sequence of test functions to be executed. Each test case must be in its own project with a source module that contains a QTEST_MAIN() macro. QTEST_MAIN() specifies which class is the entry point of this test. It expands to a main() function that creates an instance and executes its private slots in order of declaration. Additional methods for initialization and cleanup can be supplied, initTestCase() and cleanupTestCase() respectively, which get called at the begining and end of the test case.

To demonstrate the use of QTestLib, we write a test for QCOMPARE and QVERIFY, two macros that are used to make assertions inside Qt test cases. These macros can be used only in test classes, whereas Q_ASSERT can be used anywhere. On failures of assertions, they provide more information than Q_ASSERT.

Any project that uses the QTestLib module must enable it in the .pro file with this line:

   CONFIG += qtestlib
   

The first step, as shown in Example 8.5, is to define a QObject derived class that contains the test functions. It is necessary to include the QtTest header and to declare the test functions as private slots.

Example 8.5. src/libs/tests/assert/testassertequals.h

[ . . . . ]

#include <QtTest>

class TestAssertEquals:public QObject {
    Q_OBJECT
private slots:
    void test ();
};

[ . . . . ]

This test tries to verify all the various expression types. Example 8.6 is the part of the implementation that deals with bool expressions.

Example 8.6. src/libs/tests/assert/testassertequals.cpp

[ . . . . ]

void TestAssertEquals::test () {
    qDebug() << "Testing bools";
    bool boolvalue = true;
    QVERIFY (1);
    QVERIFY (true);
    QVERIFY (boolvalue);
    qDebug () << QString ("We are in file: %1  Line: %2").
            arg (__FILE__).arg (__LINE__);
    QCOMPARE (boolvalue, true);     1

1

Test EQUALS with boolean values.


Example 8.7 is the part of the implementation that deals with QString expressions.

Example 8.7. src/libs/tests/assert/testassertequals.cpp

[ . . . . ]

    qDebug() << "Testing QStrings";
    QString string1 = "apples";     1
    QString string2 = "oranges";
    QString string3 = "apples";
    QCOMPARE ("apples", "apples");  2
    QCOMPARE (string1, QString("apples"));
    QCOMPARE (QString("oranges"), string2);
    QCOMPARE (string1, string3);
    QVERIFY (string2 != string3);

1

Test EQUALS with string values.

2

test for char* comparisons with QStrings.


Example 8.8 deals with QDate and QVariant expressions. Normally, the test() function stops at the first failure, which occurs when QVERIFY(condition) encounters a false condition or QCOMPARE(actual, expected) encounters a mismatch between actual and expected. So, we have deliberately included a QCOMPARE() failure in Example 8.8 . To enable the test to continue, we have preceded the deliberate failure with a QEXPECT_FAIL() macro.

Example 8.8. src/libs/tests/assert/testassertequals.cpp

[ . . . . ]

    qDebug() << "Testing QDates";
    QString datestr ("2010-11-21");
    QDate dateobj = QDate::fromString (datestr, Qt::ISODate);
    QVERIFY (dateobj.isValid ());
    QVariant variant (dateobj);
    QString message(QString ("comparing datestr: %1 dateobj: %2 variant: %3")
           .arg (datestr).arg (dateobj.toString ()).arg (variant.toString ()));
    qDebug() << message;
    QCOMPARE (variant, QVariant(dateobj));  1
    QCOMPARE (QVariant(dateobj), variant);
    QCOMPARE (variant.toString(), datestr); 2
    QCOMPARE (datestr, variant.toString());
    QEXPECT_FAIL("","Keep going!", Continue);
    QCOMPARE (datestr, dateobj.toString()); 3

1

Comparing QDates to QVariants

2

QVariants with Strings

3

QDates and QStrings


Example 8.9 deals with expressions containing int, long, and double items. We have inserted two QVERIFY() failures in Example 8.9. We precede the first with a QEXPECT_FAIL() macro. We allow the second failure to stop the test. Note the QTEST_MAIN macro below the function definition, which generates code for an appropriate main() function.

Example 8.9. src/libs/tests/assert/testassertequals.cpp

[ . . . . ]

    qDebug() << "Testing ints and doubles";
    int i = 4; 1
    QCOMPARE (4, i);
    uint u (LONG_MAX + 1), v (u / 2);
    QCOMPARE (u, v * 2);
    double d (2. / 3.), e (d / 2);
    QVERIFY (d != e);
    QVERIFY (d == e*2);
    double f(1./3.);
    QEXPECT_FAIL("","Keep going!", Continue);
    QVERIFY (f * 3 == 2);
    qDebug() << "Testing pointers";
    void *nullpointer = 0;
    void *nonnullpointer = &d;
    QVERIFY (nullpointer != 0);
    qDebug() << "There is one more item left in the test.";
    QVERIFY (nonnullpointer != 0);
}

// Generate a main program 
QTEST_MAIN(TestAssertEquals)

1

Integer Tests


Example 8.10 shows the output of this test. Note that you do not see the output of the last qDebug() message.

Example 8.10. src/libs/tests/assert/testassert.txt

********* Start testing of TestAssertEquals *********
Config: Using QTest library 4.6.2, Qt 4.6.2
PASS   : TestAssertEquals::initTestCase()
QDEBUG : TestAssertEquals::test() Testing bools
QDEBUG : TestAssertEquals::test() "We are in file:
testassertequals.cpp  Line: 15"
QDEBUG : TestAssertEquals::test() Testing QStrings
QDEBUG : TestAssertEquals::test() Testing QDates
QDEBUG : TestAssertEquals::test() "comparing datestr: 2010-11-21
dateobj: Sun Nov 21 2010 variant: 2010-11-21"
XFAIL  : TestAssertEquals::test() Keep going!
   Loc: [testassertequals.cpp(46)]
QDEBUG : TestAssertEquals::test() Testing ints and doubles
XFAIL  : TestAssertEquals::test() Keep going!
   Loc: [testassertequals.cpp(59)]
QDEBUG : TestAssertEquals::test() Testing pointers
FAIL!  : TestAssertEquals::test() 'nullpointer != 0' returned FALSE.
()
   Loc: [testassertequals.cpp(63)]
PASS   : TestAssertEquals::cleanupTestCase()
Totals: 2 passed, 1 failed, 0 skipped
********* Finished testing of TestAssertEquals *********