The code for the header, AutoTest.h can be found below. To use it, simply:
- Add a #include "AutoTest.h" to all your QObject-derived test headers.
- Add DECLARE_TEST(YourTestClassName) below your class definition.
- Change your main.cpp to look like this:
#include "AutoTest.h"
TEST_MAIN
Easy. If you still need to supply your own main function (you might have other initialization code in here) then you can run all the tests with the following line of code:
AutoTest::run(argv, argc);
This function will return 0 if all the tests passed.
The source for AutoTest.h:
#ifndef AUTOTEST_H
#define AUTOTEST_H
#include <QTest>
#include <QList>
#include <QString>
#include <QSharedPointer>
namespace AutoTest
{
typedef QList<QObject*> TestList;
inline TestList& testList()
{
static TestList list;
return list;
}
inline bool findObject(QObject* object)
{
TestList& list = testList();
if (list.contains(object))
{
return true;
}
foreach (QObject* test, list)
{
if (test->objectName() == object->objectName())
{
return true;
}
}
return false;
}
inline void addTest(QObject* object)
{
TestList& list = testList();
if (!findObject(object))
{
list.append(object);
}
}
inline int run(int argc, char *argv[])
{
int ret = 0;
foreach (QObject* test, testList())
{
ret += QTest::qExec(test, argc, argv);
}
return ret;
}
}
template <class T>
class Test
{
public:
QSharedPointer<T> child;
Test(const QString& name) : child(new T)
{
child->setObjectName(name);
AutoTest::addTest(child.data());
}
};
#define DECLARE_TEST(className) static Test<className> t(#className);
#define TEST_MAIN \
int main(int argc, char *argv[]) \
{ \
return AutoTest::run(argc, argv); \
}
#endif // AUTOTEST_H
A typical test class header would look something like this:
#ifndef FOOTESTS_H
#define FOOTESTS_H
#include "AutoTest.h"
class FooTests : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void test1();
void test2();
void cleanupTestCase();
};
DECLARE_TEST(FooTests)
#endif // FOOTESTS_H
Apologies for the formatting - haven't worked out how to post decent looking code using blogger yet.
I'm doing something similar to this using the post-link qmake step to run the unit test binary. BUT, is there a way to rebuild the unit test after the library (or thing that you're testing) has been built so that it is updated?
ReplyDeleteYes, this is possible - I have mine setup to build and run the tests when the .lib the tests are for changes. I'll post details tomorrow.
ReplyDeleteThis automatic testing sounds great, I'll try this for my projects!
ReplyDeletegreets,
3DH
Hello, this is what I'm finding!
ReplyDeleteBut, I got these errors for my two test classes:
conflicting declaration 'Test(TestQString) t'
't' has a previous declaration as `Test(TestArray) t'
declaration of `Test(TestQString) t'
conflicts with previous declaration `Test(TestArray) t'
NOTE: "greater than" and "less than" marks are replaced by ) and ( due to editbox limitation.
I'm seeing this same issue. Any resolution?
DeleteI think I found the issue. I couldn't #include the files in the main. But now I am facing other errors, such as:
Delete1) "invalid declaration of member template in local class"
2) "local class 'class main(int, char**)::QTestClass1' shall not have static data member 'const QMetaObject main(int, char**)::QTestClass1::staticMetaObject'"
3) "local class 'class main(int, char**)::QTestClass1' shall not have static data member 'const QMetaObjectExtraData main(int, char**)::QTestClass1::staticMetaObjectExtraData'"
4) template argument for 'template class Test' uses local type 'main(int, char**)::QTestClass1'"
5) "invalid type in declaration before '(' token"
6) "initializer expression list treated as compound expression
Note: I did add an enum to the DECLARE_TEST macro and the constructor of the Test class.
I had the above errors when using the macro DECLARE_TEST in my headers instead of my cpps.
DeleteAnother workaround may be to change the macro to: #define DECLARE_TEST(className) static Test t##className(#className);
DIFF ... give me an email address and I'll email you a sample Qt4 project that uses AutoTest.h - or send me some code.
ReplyDeleteCould you post a SSCCE? I.e. a complete qt test project that runs?
ReplyDelete@Simpatico: It isn't possible to host files on here AFAIK but I'll see what I can do.
ReplyDeleteSSCCE posted - see latest entry.
ReplyDeleteGreat Work! Thx :)
ReplyDeleteI would like to say that you really made my day, it's wonderful when you just look around the web
ReplyDeleteand find something like this, reminds me of that ''How to make a dinner for a romantic...'' by Elsa Thomas,
you're a wonderful writer let me tell you!!! ñ_ñ
James Maverick (maverickhunterjames@gmail.com)
3453 Rardin Drive
San Mateo, CA 94403
Project Manager
650-627-8033
spammer!
DeleteGreat Work! Just to be sure, is this code licensed under GPL?
ReplyDeleteThanks very much, works great, only clarification I needed to debug was that you need to:
ReplyDelete# Add DECLARE_TEST(YourTestClassName) below your class DECLARATION (in the header) rather than below the definition (in the CPP file).
If you're using C++11 try this solution. http://edwrodrig.github.io/lessons/2014/05/05/testing-multiple-classes-using-c++11-lambdas-in-qt/
ReplyDelete