Qt event loop and unit testing?

TheMeaningfulEngineer picture TheMeaningfulEngineer · Feb 6, 2014 · Viewed 9.4k times · Source

I'we started experimenting with unit testing in Qt and would like to hear comments on a scenario that involves unit testing signals and slots.

Here is an example:

The code i would like to test is (m_socket is a pointer to QTcpSocket):

void CommunicationProtocol::connectToCamera()
{
    m_socket->connectToHost(m_cameraIp,m_port);
}

Since that is an asynchronous call i can't test a returned value. I would however like to test if the response signal that the socket emits on a successful connection (void connected ()) is in fact emitted.

I've written the test below:

void CommunicationProtocolTest::testConnectToCammera()
{
    QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
    communicationProtocol->connectToCamera();
    QTest::qWait(250);
    QCOMPARE(spy.count(), 1);
}

My motivation was, if the response doesn't happen in 250ms, something is wrong.

However, the signal is never caught, and I can't say for sure if it's even emitted. But I've noticed that I'm not starting the event loop anywhere in the test project. In the development project, the event loop is started in main with QCoreApplication::exec().


To sum it up, when unit testing a class that depends on signals and slots, where should the

QCoreApplication a(argc, argv);
return a.exec();

be run in the test environment?

Answer

Dan Hogan picture Dan Hogan · Nov 22, 2016

I realize this is an old thread but as I hit it and as others will, there is no answer and the answer by peter and other comments still miss the point of using QSignalSpy.

To answer you original question about "where the QCoreApplication exec function is needed", basically the answer is, it isn't. QTest and QSignalSpy already has that built in.

What you really need to do in your test case is "run" the existing event loop.

Assuming you are using Qt 5: http://doc.qt.io/qt-5/qsignalspy.html#wait

So to modify your example to use the wait function:

void CommunicationProtocolTest::testConnectToCammera()
{
    QSignalSpy spy(communicationProtocol->m_socket, SIGNAL(connected()));
    communicationProtocol->connectToCamera();

    // wait returns true if 1 or more signals was emitted
    QCOMPARE(spy.wait(250), true);

    // You can be pedantic here and double check if you want
    QCOMPARE(spy.count(), 1);
}

That should give you the desired behaviour without having to create another event loop.