I have a Qt Unit test (sub)project, which generates me one class (with the main generated by QTEST_APPLESS_MAIN
).I can start this from within Qt Creator as console app.
Q: How would I add additional classes as test cases to this particular project.
- If these classes only have "test" slots (
private Q_SLOTS
), the methods are not called, but just the ones of the class with QTEST_APPLESS_MAIN
- Since there can be only one
main(..)
, I cannot use QTEST_APPLESS_MAIN
with more than one class in the project (is that correct?)
- Of course, I can manually "wire" the slots in the (additional) classes with the one class containing the
main
, but this is very tedious.
So what is the best way to run unit test over several classes in a unit test project?
PS:
In " Using QT Unit Tests in a project - conflicting main(...) functions " a Blog is mentioned, however, I cannot download the zip describing the solution.
As per the solution you linked to, the way to accomplish testing two (or more) classes within a single Qt unit test project is to ensure that each class to be tested has a corresponding test class, and that you've created a custom int main
that executes each test class.
For example:
class TestClassA : public QObject
{
Q_OBJECT
public:
TestClassA();
...
private Q_SLOTS:
void testCase1();
...
};
class TestClassB : public QObject
{
Q_OBJECT
public:
TestClassB();
...
private Q_SLOTS:
void testCase2();
...
};
void TestClassA::testCase1()
{
// Define test here.
}
void TestClassB::testCase2()
{
// Define test here.
}
// Additional tests defined here.
// Note: This is equivalent to QTEST_APPLESS_MAIN for multiple test classes.
int main(int argc, char** argv)
{
int status = 0;
{
TestClassA tc;
status |= QTest::qExec(&tc, argc, argv);
}
{
TestClassB tc;
status |= QTest::qExec(&tc, argc, argv);
}
return status;
}
Obviously, the different test classes can be spread out over multiple translation units, then simply included in the translation unit with your int main
. Don't forget to include the appropriate .moc
files.
Based in the accepted answer and if you are using C++11 you could be interested in a solution using lambdas. It avoids you write the same code everytime. Although you can replace the lambda with a function, I think a lambda is cleaner.
#include <QtTest>
#include "test1.h"
#include "test2.h"
int main(int argc, char** argv)
{
int status = 0;
auto ASSERT_TEST = [&status, argc, argv](QObject* obj) {
status |= QTest::qExec(obj, argc, argv);
delete obj;
};
ASSERT_TEST(new Test1());
ASSERT_TEST(new Test2());
return status;
}
#ifndef TEST1_H
#define TEST1_H
Sample test
#include <QtTest>
class Test1 : public QObject
{
Q_OBJECT
private Q_SLOTS:
void testCase1();
};
Searching for this same answer, I found a very good solution from http://qtcreator.blogspot.de/2009/10/running-multiple-unit-tests.html. He creates a namespace with a container that registers all the tests created (via the DECLARE_TEST macro), and then uses it to run all the tests on the list. I rewrote it to fit my code and I post my version here (My Qt Creator version: 4.1.0):
/* BASED ON
* http://qtcreator.blogspot.de/2009/10/running-multiple-unit-tests.html
*/
#ifndef TESTCOLLECTOR_H
#define TESTCOLLECTOR_H
#include <QtTest>
#include <memory>
#include <map>
#include <string>
namespace TestCollector{
typedef std::map<std::string, std::shared_ptr<QObject> > TestList;
inline TestList& GetTestList()
{
static TestList list;
return list;
}
inline int RunAllTests(int argc, char **argv) {
int result = 0;
for (const auto&i:GetTestList()) {
result += QTest::qExec(i.second.get(), argc, argv);
}
return result;
}
template <class T>
class UnitTestClass {
public:
UnitTestClass(const std::string& pTestName) {
auto& testList = TestCollector::GetTestList();
if (0==testList.count(pTestName)) {
testList.insert(std::make_pair(pTestName, std::make_shared<T>()));
}
}
};
}
#define ADD_TEST(className) static TestCollector::UnitTestClass<className> \
test(#className);
#endif // TESTCOLLECTOR_H
Then, just add the ADD_TEST(class) line in your test header like this:
#ifndef TESTRANDOMENGINES_H
#define TESTRANDOMENGINES_H
#include <QtTest>
#include "TestCollector.h"
class TestRandomEngines : public QObject
{
Q_OBJECT
private Q_SLOTS:
void test1();
};
ADD_TEST(TestRandomEngines)
#endif // TESTRANDOMENGINES_H
And and to run all the tests, just do:
#include "TestCollector.h"
#include <iostream>
int main(int argc, char *argv[]) {
auto nFailedTests = TestCollector::RunAllTests(argc, argv);
std::cout << "Total number of failed tests: "
<< nFailedTests << std::endl;
return nFailedTests;
}
I'm using the following code to collect all test results:
#include "testclassa.h"
#include "testclassb.h"
#include <QtTest>
#include <QDebug>
int main(int argc, char** argv){
int failedTests = 0;
TestClassA testClassA
TestClassB testClassB
failedTests += QTest::qExec(&testClassA, argc, argv);
failedTests += QTest::qExec(&testClassB, argc, argv);
if(failedTests > 0){
qDebug() << "total number of failed tests: " << failedTests;
}else{
qDebug() << "all tests passed :)";
}
return failedTests;
}
The way I do it:
- Create a general "subdirs" project.
- Put the code under test in a C++ library subproject.
- Instead of using a unit test project, I use a console application subproject.
- Link the library to this console application, don't forget to handle the dependencies in the .pro file at the top of the hierarchy.
- In this console subproject, define as many test classes as you wish, and launch them in the main of this same project.
I basically made a slight variation of this post.