[ 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.
Example 8.5. src/libs/tests/assert/testassertequals.h
This test tries to verify all the various expression types.
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);
Example 8.7. src/libs/tests/assert/testassertequals.cpp
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)); QCOMPARE (QVariant(dateobj), variant); QCOMPARE (variant.toString(), datestr); QCOMPARE (datestr, variant.toString()); QEXPECT_FAIL("","Keep going!", Continue); QCOMPARE (datestr, dateobj.toString());
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; 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)
Example 8.10 shows the output of this test.
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 *********
Generated: 2012-03-02 | © 2012 Alan Ezust and Paul Ezust. |