为引用time()的方法编写测试

时间:2012-11-22 17:27:17

标签: php unit-testing phpunit

我刚开始使用PHPUnit进行单元测试,并且正在玩一些简单的方法来感受它。一个例子就是令人费解:

function setDelay($seconds)
{
    if($seconds == 0)
    {
        $this->delay = 0;
    }
    else
    {
        $this->delay = time() + $seconds;
    }
}

如果time()在方法之外未知,我如何确定正确的预期结果? :

public function testSetDelayNonZero() {
  $expected = [??];
  $this->class->setDelay(100);
  $actual = $this->class->delay;
  $this->assertEquals($expected, $actual);
}

2 个答案:

答案 0 :(得分:2)

将时间相关代码提取到单独的类是最佳选择。

然而,有时似乎有点矫枉过正。在其他语言中,可以全局设置时间,例如DateTimeUtils.setCurrentMillisFixed in java或delorean in ruby​​。

在php中你必须使用DateTime的替代品,例如来自Clock

ouzo goodies

然后在你的代码中使用:

$time = Clock::now();

在你的测试中:

//given
Clock::freeze('2011-01-02 12:34');

//when
$result = YourCode::doSomethingWithTimeReturnedByClockNow();

//then
$this->assertEquals('2011-01-02', $result);

答案 1 :(得分:1)

基本上,您需要按照您的预期测试功能,并根据您的示例提出一些小挑战。第一个简单的测试是在代码发送0秒时。此测试可能如下所示:

public function test_setDelay()
{
    this->assertEquals(0, setDelay(0));
}

要测试正确向前移动的时间,你可以模拟你的对象,所以延迟总是返回一个设定的时间加上秒,或者使用依赖注入将时间传递给函数/类来获得它,这样你就可以设置对象,然后进行调用以确保返回的时间与预期的匹配。

public function test_setDelay()
{
    this->assertEquals(0, setDelay(0));

    $setDelayMock = $this->getMock('DelayClass');
    $setDelayMock->method('setDelay')
        ->with($this->equalTo(5))
        ->will($this->returnValue('10:00:05'));
    $this->assertEquals('10:00:05', $setDelayMock->setDelay(5))
}

这实际上并不测试setDelay,但会帮助测试你之后做的事情。您希望将依赖注入发送到类中,如果它不存在,则使用time()函数。这样,您可以在代码中使用time()来调用setDelay,并将其传递给类,或者如果缺少类,则允许类在运行时创建它。但是,对于您进行测试,您始终将时间设置为已知值,而不是时间()。

$currentTime = DateTime::createfromformat('hms', '100000');    
相关问题