PHPUNIT mock with at()的工作方式很奇怪


PHPUNIT mock with at() feature works weird

下面是代码示例

<?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);或
  • 我取代模拟->预计美元($ this ->(0))通过模拟->预计美元($ this ->一次())

测试通过到绿色

有什么我不明白的吗?

编辑:

模拟->预计美元($ this -> (3))->方法("读")-> ($ this -> returnValue (' tototatatiti '));

=>

根据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

read的第二次调用使值变为1,因此它也不匹配。

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

例如,假设write方法只被调用一次,您可以像这样:
$mock->expects($this->at(0))
            ->method('write');
$mock->expects($this->at(1))
            ->method('read')
            ->will($this->returnValue('tototatatiti'));

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

我认为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));