Christopher Pisz
Christopher Pisz

Reputation: 4010

Using slots in QTest - Test case or slot?

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)

Upvotes: 1

Views: 471

Answers (1)

Christopher Pisz
Christopher Pisz

Reputation: 4010

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.

Upvotes: 1

Related Questions