【问题标题】:PHPUNIT mock with at() feature works weird具有 at() 功能的 PHPUNIT 模拟工作很奇怪
【发布时间】:2013-04-18 05:12:17
【问题描述】:

下面是代码示例

<?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)) ->方法('读取') ->will($this->returnValue('tototatatiti'));

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

【问题讨论】:

  • 看来$this->at($index) 特性不适用于指定的方法,而是适用于整个mocked对象...如果是这样的话,这完全没用!跨度>

标签: php mocking phpunit indexing


【解决方案1】:

如果模拟对象包含一些其他方法也被调用,我认为 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));

【讨论】:

    【解决方案2】:

    根据PHPUnit source code,我们有:

    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 方法之前被调用。

    【讨论】:

      猜你喜欢
      • 2013-11-03
      • 2021-05-20
      • 2014-08-15
      • 2023-03-19
      • 2011-05-07
      • 1970-01-01
      • 2016-07-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多