I'm trying to utilize QTest
in combination with Catch
and QSignalSpy
to test my applications. I have to say, that I'm using Qt 5.10.0, which might be important.
Recently I stumbled across a strange behavior, that I couldn't really explain.
main.cpp
#include "testing/catch2.hpp"
#include <QtTest/qtest.h>
#include "TestCases.h"
TEST_CASE("MyTest") {
TestCases tc;
QTest::qExec(&tc);
}
TestCases.h
#pragma once
#include <QObject>
#include <QDebug>
#include <QSignalSpy>
#include "testing/catch2.hpp"
#include "TestObject.h"
class TestCases : public QObject {
Q_OBJECT
private slots:
void firstTest() {
nameSpace::TestObject o;
QSignalSpy s(&o, &nameSpace::TestObject::valueChanged);
o.setValue();
REQUIRE(s.size() == 1);
auto var = s.takeFirst();
CHECK(var.size() == 0);
}
void secondTest() {
nameSpace::TestObject o;
QSignalSpy s(&o, &nameSpace::TestObject::objectChanged);
o.changeObject();
REQUIRE(s.size() == 1);
auto var = s.takeFirst();
CHECK(var.size() == 1);
}
};
TestObject.h
#pragma once
#include <QObject>
namespace nameSpace
{
struct MyObject
{
};
class TestObject : public QObject {
Q_OBJECT
public:
TestObject() {
}
void setValue() {
emit valueChanged();
}
void changeObject()
{
MyObject obj;
emit objectChanged(obj);
}
signals:
void valueChanged();
// Why I need to add a namespace here?
void objectChanged(const nameSpace::MyObject&);
};
}
Q_DECLARE_METATYPE(nameSpace::MyObject);
If I'll run the posted code I'll obtain the following output, which is fine for me.
********* Start testing of TestCases *********
Config: Using QtTest library 5.10.0, Qt 5.10.0 (i386-little_endian-ilp32 shared (dynamic) release build; by MSVC 2015)
PASS : TestCases::initTestCase()
PASS : TestCases::firstTest()
PASS : TestCases::secondTest()
PASS : TestCases::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped, 0 blacklisted, 9ms
********* Finished testing of TestCases *********
===============================================================================
But if I change the line void objectChanged(const nameSpace::MyObject&);
to void objectChanged(const MyObject&);
I obtain the following erroneous output:
********* Start testing of TestCases *********
Config: Using QtTest library 5.10.0, Qt 5.10.0 (i386-little_endian-ilp32 shared (dynamic) release build; by MSVC 2015)
PASS : TestCases::initTestCase()
PASS : TestCases::firstTest()
QWARN : TestCases::secondTest() QSignalSpy: Unable to handle parameter '' of type 'MyObject' of method 'objectChanged', use qRegisterMetaType to register it.
PASS : TestCases::secondTest()
PASS : TestCases::cleanupTestCase()
Totals: 4 passed, 0 failed, 0 skipped, 0 blacklisted, 7ms
********* Finished testing of TestCases *********
===============================================================================
So it is necessary to include the seemingly redundant namespace in the signal definition. Searching and finding this error took me half a day and now I also wanted to understand what might be the reason for this behavior. It is intentional or a Qt Bug? And if it is intentional, where is this in the Qt documentation.
It is somehow similar to why one has to write
Q_DECLARE_META_TYPE(nameSpace::MyObject)
instead of
namespace nameSpace {
Q_DECLARE_META_TYPE(MyObject)
}
See the docs: https://doc.qt.io/qt-5/qmetatype.html#Q_DECLARE_METATYPE.