如何在GoogleTest

时间:2015-11-20 15:08:00

标签: c++ qt googletest qtimer

我在单元测试期间遇到一些情况,我希望某些QTimer的超时在某些QObject中触发一些插槽。如何做到这一点以及这次测试的一些常见陷阱并不是很明显。

1 个答案:

答案 0 :(得分:9)

这种模式是我发现的作品。我怀疑它可能在某种程度上依赖于线程模型,因此我提供了一个YMMV的小注释。

假设你有一些

class Foo : public QObject{
  ...
  public:
  QTimer* _timer;

  public slots:
  virtual void onTimeout();
  ...
}

为简单起见,让我们假设这是一个私有实现类,这就是暴露定时器的原因,并且插槽是虚拟的,所以我们可以模拟它。

class MockFoo : public Foo{
public:
  MOCK_METHOD0(onTimeout, void());
}

首先,当使用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;
}

接下来,在测试套件中:

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);
}

关于此的一些注意事项非常重要

  1. 即使你已经在测试套件的其他地方有一个MockFoo,你需要在这一个测试中创建和销毁一个。我怀疑这与QTimer和Qt的线程模型/事件循环有关。
  2. 假设您在其他地方进行类似的测试,它可能是一个不同的类,不同的套件,不同的命名空间,一切。如果您的EXPECT_CALL在此处未饱和(或其他一些谷歌测试测试),使用此模式的下一个测试将失败,但它会抱怨此测试的预期。
    • 例如:Bar_test失败:MockFoo :: onTimeout预计会被调用一次,实际上不会被称为notisfied and active
  3. 在退出之前等待对象被销毁是很重要的。这允许Qt事件循环处理此对象上的挂起操作,即触发插槽的超时信号。
  4. 即使真正的程序使用非SingleShot计时器,在这里设置它也会简化它,这样就不会多次调用插槽,从而扰乱了测试。