Reputation: 843
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.
Upvotes: 5
Views: 3140
Reputation: 843
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:
Upvotes: 12