2

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.

Aleph0
  • 5,816
  • 4
  • 29
  • 80
  • I did not run this code but I have made a simple test, and it worked for me. I did not specify the namespace (because you are right, it is redundant) in the signal parameter structure and it worked successfully. It seems your problem is more tricky and comes from somewhere else. – Fareanor Jun 27 '19 at 08:32
  • @Fareanor: Both programs ran, but in the second case a `QWARN` is issued, if I'll omit the namespace. It is the same for you? – Aleph0 Jun 27 '19 at 08:35
  • @Fareanor: I looked inside the marco `Q_DECLARE_METATYPE()`. It actually calls `qRegisterMetaType<>`. This is really kind of odd. – Aleph0 Jun 27 '19 at 08:45
  • @Fareanor: Catch is being found here `https://github.com/catchorg/Catch2`. I think it is really a good testing framework. – Aleph0 Jun 27 '19 at 08:50
  • @Fareanor: Many thanks for your efforts to help me here. I'll try it. Maybe I can remove the catch framework from my question. Has nothing to do with the question anyway. – Aleph0 Jun 27 '19 at 09:13
  • 1
    I cleaned my comments to make this section more readable. So I have reimplemented your code without _catch2_ things. And I have the same problem than you, qRegisterMetaType() does not correct the problem. I was wrong. The slot is well called, but the QWARN is still here. – Fareanor Jun 27 '19 at 11:08
  • @Fareanor: So I guess it is a more complicated issue. Maybe it is due to the same reason one cannot use `Q_DECLARE_METATYPE` inside a namespace. At least this is in the Qt docs. – Aleph0 Jun 27 '19 at 11:09
  • Yes, this macro must be called at global scope. I think the problem is more related to the way `QSignalSpy` handles signals parameters. – Fareanor Jun 27 '19 at 11:14
  • the error is what you send const& change "void objectChanged(const nameSpace::MyObject&);" to "void objectChanged(nameSpace::MyObject);" – Vahagn Avagyan Jun 29 '19 at 19:25

0 Answers0