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

Nar*_*sus 69 php phpunit

......不知道'mock'是否是正确的词.

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

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

我正在测试的问题是我正在测试的部分代码是使用对time()的调用,所以我发现很难确切知道阈值时间应该是什么,基于我的事实我不确定何时会调用time()函数.

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

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

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

编辑:我的问题的一部分也是历史中发生的事情影响阈值的事实.这是我的部分问题的一个例子......

想象一下,你有一个香蕉,当你需要吃它时,你正试图解决这个问题.假设它将在3天内到期,除非它喷洒了一些化学物质,在这种情况下,我们会在施用喷雾时添加4天到期.然后,我们可以通过冻结它再添加3个月,但是如果它已经冷冻,那么我们只有1天的时间来解冻它.

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

正如您可能或可能无法分辨的那样,我仍然试图了解所有这些"测试"概念;)

Fab*_*ler 59

我最近提出了另一种解决方案,如果你使用的是PHP 5.3名称空间.您可以在当前命名空间内实现新的time()函数,并创建一个共享资源,您可以在其中设置测试中的返回值.然后对time()的任何不合格的调用都将使用你的新函数.

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

  • 我最近实现了库[php-mock](https://github.com/malkusch/php-mock),它使用该语言功能来模拟非确定性PHP函数,如`time()`. (2认同)
  • 好的解决方案 即使您的SUT位于与测试不同的命名空间中,也可以通过在同一文件中使用"多个命名空间"来使用它http://php.net/manual/en/language.namespaces.definitionmultiple.php (2认同)

Hen*_*ley 10

Carbon::setTestNow(Carbon $time = null)进行任何调用Carbon::now()new Carbon('now')同时返回。

https://medium.com/@stefanledin/mock-date-and-time-with-carbon-8a9f72cb843d

例子:

    public function testSomething()
    {
        $now = Carbon::now();
        // Mock Carbon::now() / new Carbon('now') to always return the same time
        Carbon::setTestNow($now);

        // Do the time sensitive test:
        $this->retroEncabulator('prefabulate')
            ->assertJsonFragment(['whenDidThisHappen' => $now->timestamp])

        // Release the Carbon::now() mock
        Carbon::setTestNow();
    }
Run Code Online (Sandbox Code Playgroud)

当然该$this->retroEncabulator()函数需要Carbon::now()在内部使用。new Carbon('now')


Pio*_*ski 6

免责声明:我写了这个库.

你可以嘲笑时间使用测试时钟茴香烈酒,好吃的东西.

在代码中使用简单:

$time = Clock::now();
Run Code Online (Sandbox Code Playgroud)

然后在测试中:

Clock::freeze('2014-01-07 12:34');
$result = Class::getCurrDate();
$this->assertEquals('2014-01-07', $result);
Run Code Online (Sandbox Code Playgroud)

  • 当您链接到自己的软件时,您应该包含免责声明,让每个人都知道您编写了它. (26认同)

Sen*_*enG 5

我必须在应用程序本身(而不是在单元测试中)模拟未来和过去日期的特定请求。因此,对 \DateTime::now() 的所有调用都应返回之前在整个应用程序中设置的日期。

我决定使用这个库https://github.com/rezzza/TimeTraveler,因为我可以在不更改所有代码的情况下模拟日期。

\Rezzza\TimeTraveler::enable();
\Rezzza\TimeTraveler::moveTo('2011-06-10 11:00:00');

var_dump(new \DateTime());           // 2011-06-10 11:00:00
var_dump(new \DateTime('+2 hours')); // 2011-06-10 13:00:00
Run Code Online (Sandbox Code Playgroud)


sim*_*.ro 5

对于那些你用symfony(> = 2.8)工作:Symfony的的PHPUnit的桥包括一个ClockMock功能,覆盖内建的方法timemicrotimesleepusleep

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