Pros and cons
Why use Qt Test for unit testing and TDD (test-driven development)?
- small testing framework (about 6K lines of source code);
- seamless integration with QtCreator development environment;
- full support of Qt framework including classes/types and signal/slots;
- simple to start and use.
However, there are some drawbacks, too.
- designed as "single testing class per test project"; Qt developers use test project hierarchy themselves with
SUBDIRS
;
TEMPLATE = subdirs SUBDIRS += \ test_of_unit1 \ test_of_unit2 \ ...
- no mocks;
- checking functions/macros doesn't support some standard types i.e. wide strings and literals;
- Qt dependency: a test executable requires some DLL to run (
QtTest
andQtCore
at least, static linking is allowed in commercial version only).
Some of these limitation may be removed using the following workarounds.
Multiple Qt testing classes in a single project
Create test project and add new testing classes as it described in the Qt manuals.
Remove any declarations like QTEST_MAIN(MyTest1)
from testing class files.
You need to add the main C++ source file to the project, i.e. bootstrap.cpp
. Include test class files to bootstrap.cpp
and write the main function as following:
#include <QtTest> // Testing classes #include "MyTest1.h" #include "MyTest2.h" int main(int argc, char *argv[]) { int status = 0; QTest::setMainSourcePath(__FILE__, QT_TESTCASE_BUILDDIR); { MyTest1 tc; status |= QTest::qExec(&tc, argc, argv); } { MyTest2 tc; status |= QTest::qExec(&tc, argc, argv); } return status; }
From now QtCreator test explorer shows all test results.
Testing strings
QCOMPARE
doesn't seem to test wide-character literals L"Abc"
, std::wstring
and even std::string
values correctly, there is no additional information showing when a check is failed. Fortunately, you can add some simple macros to compare strings.
#define QSCOMPARE(string1, string2) {\ QByteArray ba1 = QString::fromStdString(string1).toLocal8Bit(); \ QByteArray ba2 = QString::fromStdString(string2).toLocal8Bit(); \ const char *ps1 = ba1.data(), *ps2 = ba2.data(); \ QTest::compare_helper(static_cast<bool>(string1 == string2), \ "Compared strings are not the same", \ QTest::toString(ps1), QTest::toString(ps2), \ #string1, #string2, \ __FILE__, __LINE__); \ } // #define QWSCOMPARE(wstring1, wstring2) {\ QByteArray ba1 = QString::fromStdWString(wstring1).toUtf8(); \ QByteArray ba2 = QString::fromStdWString(wstring2).toUtf8(); \ const char *ps1 = ba1.data(), *ps2 = ba2.data(); \ QTest::compare_helper(static_cast<bool>(wstring1 == wstring2), \ "Compared wide strings are not the same", \ QTest::toString(ps1), QTest::toString(ps2), \ #wstring1, #wstring2, \ __FILE__, __LINE__); \ } //
Afterword
Being testing QtTest framework when migrating from Microsoft CppUnit one, I realized quickly these limitations. However, my project isn't based on Qt framework so I didn't have big advantages of using QtTest even after workarounds have been found. On the other hand QtTest is still a good choice when you develop Qt-based applications.