1

I am trying to build a test using qtest, to exercise my library which implements a class that wrapped QWebSocket.

It looks like QTest will run every method under "private slots:" and thinks that it is test init, cleanup, or a test case.

However, I am also trying to bring up a server on localhost with which to connect to and that requires slots to be called back when the listener accepts a connection and closes, etc.

QTest wants to treat those callbacks as test cases, and runs them, which is not correct. How do I tell it "these are slots for your test cases" and "these are slots that are used elsewhere?"

Consider this test code:

#include <QCoreApplication>
#include <QtTest>
#include <QtWebSockets/qwebsocket.h>
#include <QtWebSockets/qwebsocketserver.h>
#include <string>

class qtwebstompclientimpl_tests : public QObject
{
    Q_OBJECT

public:
    qtwebstompclientimpl_tests();
    ~qtwebstompclientimpl_tests();

private slots:
    void initTestCase();
    void cleanupTestCase();
    void onAccept();                 // Wants to run these as test cases, but they are actually slots for QWebSocketServer
    void onAcceptError(QAbstractSocket::SocketError socketError);
    void onTextReceived(QString message);
    void onClientClosed();
    void test_case1();

private:
    QWebSocketServer * m_webSocketServer;
    QWebSocket * m_connectedWebsocketClient;
    bool m_errorOccurred;
    QString m_lastMessage;
};

qtwebstompclientimpl_tests::qtwebstompclientimpl_tests() {}

qtwebstompclientimpl_tests::~qtwebstompclientimpl_tests() {}

void qtwebstompclientimpl_tests::initTestCase()
{
    m_webSocketServer = new QWebSocketServer("Test Server", QWebSocketServer::NonSecureMode);
    if( !m_webSocketServer->listen(QHostAddress::Any, 5000) )
    {
        std::string errorMessage = m_webSocketServer->errorString().toStdString();
        throw std::runtime_error("Failed to setup test websocket server - Listen failed");
        connect(m_webSocketServer, &QWebSocketServer::newConnection, this, &qtwebstompclientimpl_tests::onAccept);
        connect(m_webSocketServer, &QWebSocketServer::acceptError, this, &qtwebstompclientimpl_tests::onAcceptError);
    }

    m_connectedWebsocketClient = nullptr;
    m_errorOccurred = false;
}

void qtwebstompclientimpl_tests::cleanupTestCase()
{
    if( m_connectedWebsocketClient )
    {
        delete m_connectedWebsocketClient;
    }
    delete m_testClient;
    delete m_webSocketServer;
}

void qtwebstompclientimpl_tests::onAccept()
{
    if(m_connectedWebsocketClient)
    {
        m_connectedWebsocketClient->close();
    }

    m_connectedWebsocketClient = m_webSocketServer->nextPendingConnection();

    connect(m_connectedWebsocketClient, &QWebSocket::textMessageReceived, this, &qtwebstompclientimpl_tests::onTextReceived);
    connect(m_connectedWebsocketClient, &QWebSocket::disconnected, this, &qtwebstompclientimpl_tests::onClientClosed);
}

void qtwebstompclientimpl_tests::onAcceptError(QAbstractSocket::SocketError socketError)
{
    m_errorOccurred = true;
}

void qtwebstompclientimpl_tests::onTextReceived(QString message)
{
    QWebSocket * client = qobject_cast<QWebSocket *>(sender());
    if(client == m_connectedWebsocketClient)
    {
        m_lastMessage = message;
    }
}

void qtwebstompclientimpl_tests::onClientClosed()
{
    QWebSocket * client = qobject_cast<QWebSocket *>(sender());
    if(client == m_connectedWebsocketClient)
    {
        m_connectedWebsocketClient->deleteLater();
    }
}

void qtwebstompclientimpl_tests::test_case1()
{
    QVERIFY(true);
}

QTEST_MAIN(qtwebstompclientimpl_tests)
Christopher Pisz
  • 3,757
  • 4
  • 29
  • 65
  • try QSignalSpy, – Vahagn Avagyan May 25 '20 at 21:40
  • Looked up QSignalSpy. I don't think that is going to help me, because the QWebSocketServer class from QT is never even going to fire its slot when a client connects, in order to allow for a data to be received and that sigal to be tested with QSignalSpy. i.e Qt's socket wants to go through the process of connecting before emitting signals for the rest of its slots. On the otherhand, QTest itself seems to process unit tests as slots, which prevents other slots from being called. – Christopher Pisz May 25 '20 at 22:05

1 Answers1

1

Solved by using a combination of

  • Moving the other slots to public scope. QTest only seems to test the slots in private scope.
  • Using qQwait, which allows other events to be handled, including the slot for the socket.

qWait has the unfortunate side effect of making my unit tests unnecessarily long, as we have to "guess" at a high enough interval to allow the other slots to process. We also, much like with a sleep, will have to make sure its high enough and crank it up when debugging to allow enough time to step through code.

Christopher Pisz
  • 3,757
  • 4
  • 29
  • 65