使用at()功能的PHPUNIT模拟工作很奇怪

时间:2013-04-24 15:08:57

标签: php mocking phpunit indexing

这是以下代码示例

<?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和($ index)功能发生一些奇怪的事情。

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

我明确地要求返回&#34; tototatatiti&#34;,但它永远不会发生......

何时

  • 我删除了行$ this-&gt; _fs-&gt; write($ elm); 或
  • 我替换$ mock-&gt;期望($ this-&gt; at(0))$ mock-&gt; expect($ this-&gt; once())

测试传递给绿色

有什么我不明白的吗?

编辑:

$模拟转&GT;期待($这 - &GT;在(3))                  - &GT;方法(&#39;读&#39;)                  - &GT;将($这 - &GT;的returnValue(&#39; tototatatiti&#39;));

=&GT;将使测试通过绿色...

2 个答案:

答案 0 :(得分:3)

根据PHPUnit source code我们有:

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

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

每次PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex尝试匹配调用时,受保护变量$currentIndex都会递增,因此您先写入的调用会使其变为0,然后它与{{1}不匹配}。

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

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

例如,假设read方法仅被调用一次,您可以使用以下内容:

write

这确保$mock->expects($this->at(0)) ->method('write'); $mock->expects($this->at(1)) ->method('read') ->will($this->returnValue('tototatatiti')); 方法确实在write方法之前调用。

答案 1 :(得分: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));