我可以在PHPUnit中“模拟”时间吗?

2022-08-30 08:33:26

...不知道“嘲笑”是否是正确的词。

无论如何,我有一个继承的代码库,我正在尝试为它编写一些基于时间的测试。为了尽量不要模糊,代码与查看项目的历史记录并确定该项目现在是否基于时间阈值有关。

在某些时候,我还需要测试向该历史记录中添加一些内容,并检查阈值现在是否已更改(显然,正确)。

我遇到的问题是,我正在测试的代码的一部分是使用对time()的调用,所以我发现很难确切地知道阈值时间应该是多少,因为我不确定何时会调用该time()函数。

所以我的问题基本上是这样的:我有没有办法“覆盖”time()调用,或者以某种方式“模拟”时间,这样我的测试在“已知时间”工作?

或者我只需要接受这样一个事实,即我必须在我正在测试的代码中做一些事情,以某种方式允许我在需要时强制它使用特定的时间?

无论哪种方式,是否有任何“常见做法”来开发对测试友好的时间敏感型功能?

编辑:我的部分问题也是,历史上发生的事情的时间会影响阈值。这是我的部分问题的示例...

想象一下,你有一根香蕉,你正试图弄清楚什么时候需要吃掉它。假设它将在3天内过期,除非它喷洒了一些化学物质,在这种情况下,我们从喷洒时起增加4天的有效期。然后,我们可以通过冷冻它来再增加3个月,但是如果它被冷冻了,那么在它解冻后我们只有1天的时间来使用它。

所有这些规则都是由历史时间决定的。我同意我可以使用Dominik的建议在几秒钟内进行测试,但是我的历史数据呢?我应该在飞行中“创建”它吗?

正如你可能或可能不会说的那样,我仍然试图掌握所有这些“测试”概念;)


答案 1

我最近想出了另一个解决方案,如果您使用的是PHP 5.3命名空间,那么这个解决方案非常棒。您可以在当前命名空间中实现新的 time() 函数,并创建一个共享资源,您可以在其中设置测试中的返回值。然后,对 time() 的任何非限定调用都将使用您的新函数。

为了进一步阅读,我在我的博客中详细描述了它


答案 2

对于那些使用symfony(>= 2.8)的人来说:Symfony的PHPUnit Bridge包括一个ClockMock功能,该功能覆盖了内置方法,和。timemicrotimesleepusleep

请参见: http://symfony.com/doc/2.8/components/phpunit_bridge.html#clock-mocking


推荐