PDA

View Full Version : QtTest - use it in your application



migel
20th December 2011, 13:54
I am little concerned that I should use my .pro file to include CONFIG += qtestlib.

I would like to write testing classes for my project. But is that mean that all testing classes will be build into my project ? How to hook up QtTest to existing project. Should it be a separate Testing project which includes to your testing.pro all headers and sources from project ?

Thanks

stampede
20th December 2011, 14:08
You can just create a seciton in you .pro file, something like this:


// project.pro

// some regular stuff
INCLUDEPATH += ...
SOURCES += ..
// etc

// here for testing
test_conf{
TARGET = my_app_test # different app name for testing suite
QT += testlib
SOURCES += test.cpp test2.cpp
HEADERS += test.h ...
... other stuff for tests
}


Then you can generate makefiles for test with qmake:


qmake -config test_conf

After that, simply build the project as usual. Instead of your regular target, a my_app_test.exe will be created, using your test sources.

migel
21st December 2011, 10:04
Hi, thanks for answer.

I am trying to build the first test but sort of does not work


test.h:15: error: multiple definition of `main'

This is the knows issue. Adding a lines below tare not helping


#ifdef Q_WS_X11
QTEST_MAIN(Test)
#include "test.moc"
#else
QTEST_NOOP_MAIN
#endif

A file #include "test.moc" does not exists. I have tried with out it too. Base on this howto all I am doing is correct. so what's wrong ?

http://developer.qt.nokia.com/doc/qt-4.8/qtestlib-tutorial1.html#id-fcc2609c-6c8f-4a32-9b7a-ea7744df50ea

fullmetalcoder
21st December 2011, 12:35
test.h:15: error: multiple definition of `main'
When building unit tests, QtTest provides its own main function so you should not build the main function of your actual application.


test_conf {
# test specific files and options here
SOURCEs += test.cpp
...
} else {
# app specific files and options here
SOURCEs += main.cpp
...
}

# common stuff here

migel
21st December 2011, 13:16
Yes I have done that. And it still complaining

I have ran make clean, removed project.pro.user, removed Makefile manually and re ran the qmake -config test_conf.


test.h:15: error: multiple definition of `main'
test.h:15: error: first defined here
:-1: error: collect2: ld returned 1 exit status


line 15: QTEST_MAIN(Test)

What else I can do ?

Found the problem

QTEST_MAIN(Test) should be in source file .cpp not in the header.

Thanks for all your help.

migel
22nd December 2011, 16:33
One more thing to ask.

I have two classes for testing, and how to run all tests from both classes the same time if I can't add


QTEST_MAIN(Test1)

and


QTEST_MAIN(Test2)

the same time ?

If I will enable it in both classes a compiler complains about the main method


test1.cpp:57: error: multiple definition of `main'
test2.cpp:24: error: first defined here
:-1: error: collect2: ld returned 1 exit status

Thanks

fullmetalcoder
22nd December 2011, 17:51
The QTEST_MAIN macro creates a main function so you can only have one per application. The standard approach is to have a different executable for each unit test. This is easy to do with CMake, but more annoying with qmake. An alternative is to write your own main function that does multiple unit tests.

The code below could prove useful if you take the second path :


// header

class Test {
public:
static Test* get();


int runAll(int argc, char **argv);
void addTestObject(QObject *o);


private:
Test();
~Test();


QList<QObject*> m_testObjects;
};


template <class T>
class TestRegistar {
public:
inline TestRegistar(const char *name) {
T *test = new T;
test->setObjectName(name);
Test::get()->addTestObject(test);
}
};

#define TEST(T) \
static ::TestRegistar<T> _test_registar_##T(""#T);





//source


Test* Test::get() {
static Test inst;
return &inst;
}


/*!
\brief Run all unit tests


The following arguments are recognized :
<ul>
<li>--restrict : only run tests to which an option is passed
<li>@&lt;testname&gt;[:&lt;option&gt;] : pass an argument to a single test.
The test will be run with --restrict on even if the option is empty
</ul>
All other arguments are forwarded to all unit tests. Arguments passed to test
can be any of those supported by regular QtTest-based unit tests.
*/
int Test::runAll(int argc, char **argv) {
bool restrict = false;
QStringList common;
QHash<QString, QStringList> specific;
for (int i = 0; i < argc; ++i) {
QString s = QString::fromLocal8Bit(argv[i]);
if (i && *argv[i] == '@') {
int idx = s.indexOf(':');
if (idx != -1)
specific[s.mid(1, idx - 1)] << s.mid(idx + 1);
else
specific[s.mid(1)] = specific.value(s.mid(1));
} else if (!qstrcmp(argv[i], "--restrict")) {
restrict = true;
} else {
common << s;
}
}


int ret = 0;
foreach (QObject *o, m_testObjects) {
if (restrict && !specific.contains(o->objectName()))
continue;
QStringList args = common;
args << specific.value(o->objectName());
if ((ret = QTest::qExec(o, args)))
break;
}
return ret;
}


void Test::addTestObject(QObject *o) {
m_testObjects << o;
}


Test::Test() {
}



Test::~Test() {
qDeleteAll(m_testObjects);
}


With that, you can register multiple unit test classes with the TEST macro and invoke them all from anywhere you fancy (but most likely from a main()) via "Test::get()->runAll(argc, argv)"