如何使用模拟框架在谷歌测试延迟后测试呼叫

时间:2016-01-08 19:01:14

标签: c++ unit-testing googletest gmock fakeit

我目前正在尝试评估不同的测试框架。当使用模拟框架时(我倾向于FakeIt,但谷歌模拟也很好),我知道你可以推出自己的"性能"在调用函数之前和之后使用OS的定时器调用进行测试,以验证函数的性能。这不是我之后的事。

我所拥有的是在给定某些输入的情况下实现输出延迟的类。例如:

  • 输入1从低到高
  • 输出1在 1.5秒后从低到高

我希望能够在指定边界的地方做点什么:

myMock.theInput();
EXPECT_CALL(myMock, theDelayedOutput())
  .Times(1)
  .Before(1.6sec)
  .After(1.4sec);

为了澄清,不支持BeforeAfter行。这只是我喜欢的一种简单语法的例子。

是否可以实施"延迟"在进行输入调用之前和检查EXPECT_CALL之前的窗口内的函数?

这方面的一部分 - 我仍然需要启动专有计时器。像这样的东西?

myMock.theInput();
windowSleep(1.4);
startTimer();
EXPECT_CALL(myMock, theDelayedOutput())
  .Times(1)
endTimer();
ASSERT_TRUE(elapsedTime() <= 0.2);

2 个答案:

答案 0 :(得分:1)

我很确定这个解决方案适用于任何框架而无需修改框架:

myMock.theInput();
startTimer();
EXPECT_CALL(myMock, theDelayedOutput());
endTimer();
ASSERT_TRUE(elapsedTime() >= 1.4);
ASSERT_TRUE(elapsedTime() <= 1.6);

然后可以将其包装在宏中:

#define EXPECT_CALL_DELAYED(theMock, expectCall, lowerBound, upperBound) {\
  startTimer();\
  EXPECT_CALL(theMock, expectCall);\
  endTimer();\
  ASSERT_TRUE(elapsedTime() >= lowerBound);\
  ASSERT_TRUE(elapsedTime() <= upperBound);\
}

最终的测试代码是:

myMock.theInput();
EXPECT_CALL_DELAYED(myMock, theDelayedOutput(), 1.4, 1.6);

或者,您可以遵守DRY原则并预先指定时间的“窗口”。这允许你测试,指定精确的时间,但没有重复你自己不得不每次上下添加0.1秒缓冲区的缺点。

EXPECT_CALL_DELAYED_SET_WINDOW(0.1);
myMock.theInput();
EXPECT_CALL_DELAYED(myMock, theDelayedOutput(), 1.5);
myMock.theSecondInput();
EXPECT_CALL_DELAYED(myMock, theSecondDelayedOutput(), 3.1);
但是,我还没有测试过这些。我会稍后更新并接受是否有效。

答案 1 :(得分:0)

由于您使用单元测试标记了问题:在单元测试中,您的测试不应该依赖于物理时间的传递。这有多种原因:一个是您希望测试尽快运行,因此您不需要延迟。另一个原因是开发环境(运行单元测试)的时间可能与目标环境完全不同,因为硬件,操作系统,系统负载不同......

也就是说,涉及物理时间过去的测试确实有意义,但它们将是目标系统上的集成测试(或其某些模拟)。在单元测试中,您将采用不同的方法:

你会模拟代表你的时钟的函数/方法。例如,如果您的函数funcA通过setTimer设置一个计时器,则提供一个在时间过去时调用的回调:

  • 在一些测试中,您模拟setTimer函数,调用funcA,并且,作为测试的传递标准的一部分,检查是否使用您期望的参数调用了模拟的setTimer。
  • 在其他一些测试中,您可以直接从测试中调用回调函数,以查看该函数是否正常运行。

在这两个单元测试案例中,您都不会等待物理时间过去。

也就是说,您当然可以使用相同的测试框架来进行单元测试,也可以用于集成测试(即使它们的名称,如JUnit,似乎表明它们仅用于单元测试)。而且,如果集成测试实际上是您所针对的测试类型,那么来自Jeff Lamb的建议肯定会有所帮助。