0

I am investigating QTest for GUI testing. It appears that there is no mechanism in QTest to asynchronously test a signal callback. Am I misunderstanding how to use QTest, or misunderstanding the intended functionality provided by QTest?

For example, I am attempting to test a signal which launches a modal QMessageBox popup in response to clicking a QPushButton. I want to test events and state between the clicking of the button and clicking 'OK' on the QMessageBox. I have tried using QSignalSpy.wait(), QTestEventList.simulate(), QTest::mouseClick(), QTest::mouseEvent(), and QTRY_VERIFY(), all of which, when called from the testing code, do not return until after clicking 'OK' on the QMessageBox popup. Therefore, to test anything before all event handlers return, I would have to do something like install an event filter on the object under test, and write my own asynchronous testing code.

This is all the same code we would have to write if we weren't using a test library and we can do all of this without using QTest. For example, we can manually get a handle to the object under test, connect signals for testing, invoke an event to trigger the event handler or invoke the signal manually, and also write the installed test handlers that interact with the test environment before returning execution to the point at which the event was launched. What does QTest gain us here?

(Also posted on Qt forums)

Zargontapel
  • 298
  • 1
  • 2
  • 12
taz
  • 1,506
  • 3
  • 15
  • 26

1 Answers1

1

Working with synchronous events using qtestlib is a bit tricky. If you look into the sources of qtestlib, you can find that event simulation are pretty straightforward. So, qtestlib doesn't provide any methods to handle synchronous events. Anyway, it's possible to handle Qt modal windows which are spawned by your app.

Main note to this question is that GUI objects can't be accessed from others threads except GUI thread. And moreover GUI could be created only in thread where QApplication was created. So some tricks like spawning a new thread to press OK button in QMessageBox will be unsuccessful with error like this object can not be accessed from other thread somewhere in QWidget sources.

To avoid this case async event could be triggered with Qt slots mechanism. First of all you should define a Helper object with some slot, for example

class Helper {
    Helper() {}
    public slots:
        doSmth();
}

Further you should create an instance of this object in the testcase

void BlahblahTest::testCase1() {
    Helper h;
...

And before you invoke some synchronous event with, for example, QTest::mouseClick, set a delayed action with

QTimer::singleShot(delay, &h, SLOT(doSmth));

Depends on your needs the implementation of doSmth could be like that

void Helper::doSmth() {
    QList<QWidget *> tlw = qApp()->topLevelWidgets();
    foreach (QWidget *w, tlw) {
        if (...) { // w is a messagebox
            Qt::keyClick(w, Qt::Key_Enter);
        }
    }
}
ujohnny
  • 111
  • 1
  • 2