2

这是以下代码示例

<?php

interface iFS
{
    public function read();
    public function write($data);
}

class MyClass
{
    protected $_fs = null;

    public function __construct(iFS $fs)
    {
        $this->_fs = $fs;
    }

    public function run(array $list)
    {
        foreach ($list as $elm)
        {
            $this->_fs->write($elm);
        }

        return $this->_fs->read();
    }
}

class MyTests extends PHPUnit_Framework_TestCase
{
    public function testFS()
    {
        $mock = $this->getMock('iFS');
        $mock->expects($this->at(0))
                ->method('read')
                ->will($this->returnValue('tototatatiti'));

        $c = new MyClass($mock);
        $result = $c->run(array('toto', 'tata', 'titi'));

        $this->assertEquals('tototatatiti', $result);
    }
}

这绝对不是一个真实的案例,但它使 phpunit 和 at($index) 功能发生了一些奇怪的事情。

我的问题很简单,测试失败正常吗?

我明确要求返回“tototatatiti”,但它从未发生过......

什么时候

  • 我删除了 $this->_fs->write($elm); 行 或者
  • 我将 $mock->expects($this->at(0)) 替换为 $mock->expects($this->once())

测试通过绿色

有什么我不明白的吗?

编辑:

$mock->expects($this->at(3)) ->method('read') ->will($this->returnValue('tototatatiti'));

=> 将使测试通过绿色...

4

2 回答 2

3

根据PHPUnit 源代码,我们有:

public function matches(PHPUnit_Framework_MockObject_Invocation $invocation)
{
    $this->currentIndex++;

    return $this->currentIndex == $this->sequenceIndex;
}

每次PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex尝试匹配调用时,受保护的变量$currentIndex都会递增,因此您首先调用 write 会导致它变为 0,然后它不匹配read

第二次调用 toread导致值变为 1,因此它也不匹配。

看起来它确实适用于整个对象,如果您需要确保一系列调用以特定顺序发生,这很有用。

例如,假设该write方法只被调用一次,你可以有类似的东西:

$mock->expects($this->at(0))
            ->method('write');

$mock->expects($this->at(1))
            ->method('read')
            ->will($this->returnValue('tototatatiti'));

这确保了该write方法确实在该read方法之前被调用。

于 2013-04-24T16:13:05.250 回答
0

我认为如果模拟对象包含一些其他方法也被调用,那么 phpunit at() 功能对于模拟方法的不同返回结果存根是没有用的......

如果你想测试类似的东西:

$stub->expects($this->at(0))
                ->method('read')
                ->will($this->returnValue("toto"));

$stub->expects($this->at(1))
                ->method('read')
                ->will($this->returnValue("tata"));

你最好使用类似的东西

$stub->expects($this->exactly(2))
                ->method('read')
                ->will($this->onConsecutiveCalls("toto", "tata));
于 2013-04-25T08:43:04.670 回答