I encounter cases during unit testing where I want the timeout of some QTimer to fire some slot in some QObject. It is not immediately obvious how to do this and some common pitfalls to this testing.
This pattern is the one I've found works. I suspect it may be somewhat dependent on threading models, so I provide it with a minor note of YMMV.
Suppose you have some
class Foo : public QObject{
...
public:
QTimer* _timer;
public slots:
virtual void onTimeout();
...
}
for simplicity, let's pretend this is some private implementation class, which is why the timer is exposed, and the slot is virtual so we can mock it.
class MockFoo : public Foo{
public:
MOCK_METHOD0(onTimeout, void());
}
First¸ generally when using QTimers and other threading model stuff from Qt, we must modify the 'main' function of google test:
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
::testing::InitGoogleTest(&argc, argv);
int ret = RUN_ALL_TESTS();
QTimer exitTimer;
QObject::connect(&exitTimer, &QTimer::timeout, &app, QCoreApplication::quit);
exitTimer.start();
app.exec();
return ret;
}
Next, in the test suite:
TEST_F(Foo_Tests, onTimeout){
MockFoo* foo{new MockFoo};
//using Qt 5 convention, but do what you gotta do for signal spy in your setup
QSignalSpy timeoutSpy(foo->_timer, &QTimer::timeout);
QSignalSpy deleteSpy(foo, &QObject::destroyed);
foo->_timer->setInterval(0);
foo->_timer->setSingleShot(true);
EXPECT_CALL(*foo, onTimeout());
foo->_timer->start();
EXPECT_TRUE(timeoutSpy.wait(100));
foo->deleteLater();
deleteSpy.wait(100);
}
Some notes about this that are very important:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With