简体   繁体   English

如何在GoogleTest中使用QTimers

[英]How to use QTimers in GoogleTest

I encounter cases during unit testing where I want the timeout of some QTimer to fire some slot in some QObject. 我在单元测试期间遇到一些情况,我希望某些QTimer的超时在某个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. 我怀疑它可能在某种程度上依赖于线程模型,因此我提供了一个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: 首先,当使用Qt中的QTimers和其他线程模型时,我们必须修改google test的'main'功能:

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 : 关于这一点的一些注意事项非常重要

  1. Even if you have a MockFoo already elsewhere in the testsuite, you need one that is created and destroyed within this one test. 即使你已经在测试套件中的其他地方有一个MockFoo,你需要在这一个测试中创建和销毁一个。 I suspect this has to do with QTimer and Qt's threading model/event loop. 我怀疑这与QTimer和Qt的线程模型/事件循环有关。
  2. Suppose you do a similar test elsewhere, it could be a different class, different suite, different namespace, everything. 假设你在别处做了类似的测试,它可能是一个不同的类,不同的套件,不同的命名空间,一切。 If your EXPECT_CALL is not saturated here (or some other google test test), the next test using this pattern will fail, but it will complain about this test's expectations. 如果您的EXPECT_CALL在此处未饱和(或其他一些谷歌测试测试),使用此模式的下一个测试将失败,但它会抱怨此测试的预期。
    • eg: Bar_test failed: MockFoo::onTimeout expected to be called once actual not called unsatisfied and active 例如:Bar_test失败:MockFoo :: onTimeout预计会被调用一次,实际上不被称为notisfied和active
  3. It is important to wait for the object to be destroyed before exiting. 在退出之前等待对象被销毁是很重要的。 This allows the Qt event loop to process the pending actions on this object, namely the timeout signal that fires the slot. 这允许Qt事件循环处理此对象上的挂起操作,即触发插槽的超时信号。
  4. Even if the real program uses a non SingleShot timer, setting it that way here simplifies it so that the slot isn't called multiple times, upsetting the test. 即使真正的程序使用非SingleShot计时器,在这里设置它也会简化它,以便不会多次调用插槽,从而扰乱测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM