2

我目前正在尝试评估不同的测试框架。在使用模拟框架时(我倾向于 FakeIt,但 google mock 也很好),我知道您可以通过在调用函数之前和之后使用操作系统的计时器调用来滚动自己的“性能”测试来验证函数的性能。这不是我所追求的。

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

  • 输入 1 从低到高
  • 输出 1 在1.5 秒从低电平变为高电平。

我希望能够做一些我指定边界的事情:

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

为澄清起见,不支持Before和行。After这只是我喜欢的简单语法的一个例子。

是否可以在进行输入调用和检查之前在窗口中实现“延迟”功能EXPECT_CALL

这是其中的一部分——我仍然需要启动一个专有计时器。像这样的东西?

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

2 回答 2

2

既然你用单元测试标记了这个问题:在单元测试中,你的测试不应该依赖于物理时间的流逝。这有多种原因:一个是您希望测试尽快运行,因此您不希望出现延迟。另一个原因是开发环境(运行单元测试的地方)的时间可能与目标环境完全不同,因为不同的硬件、操作系统、系统负载……

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

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

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

在这两种单元测试用例中,您不必等待物理时间过去。

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

于 2016-02-05T23:52:32.790 回答
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);

不过,我还没有测试过这些。我稍后会更新并接受是否可行。

于 2016-01-08T21:00:25.247 回答