PHPUnit"Mocked方法不存在".当使用$ mock-> expected($ this-> at(...))时

rr.*_*rr. 38 php phpunit unit-testing mocking

我遇到了PHPUnit模拟对象的一个​​奇怪问题.我有一个应该被调用两次的方法,所以我使用的是"at"匹配器.这是第一次调用该方法,但由于某种原因,第二次调用它时,我得到"模拟方法不存在".我之前使用过"at"匹配器并且从未遇到过这种情况.

我的代码看起来像:

class MyTest extends PHPUnit_Framework_TestCase
{
    ...

    public function testThis()
    {
        $mock = $this->getMock('MyClass', array('exists', 'another_method', '...'));
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

当我运行测试时,我得到:

Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1.
Mocked method does not exist.
Run Code Online (Sandbox Code Playgroud)

如果我删除第二个匹配器,我不会收到错误.

有没有人遇到过这个?

谢谢!

rr.*_*rr. 42

问题最终与我如何理解"at"匹配器的工作方式有关.另外,我的例子并非逐字逐句地在我的单元测试中.我认为"at"匹配器计数器在每个查询的基础上工作,它真正适用于每个对象实例.

例:

class MyClass {

    public function exists($foo) {
        return false;
    }

    public function find($foo) {
        return $foo;
    }
}
Run Code Online (Sandbox Code Playgroud)

不正确:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(0))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(1))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}
Run Code Online (Sandbox Code Playgroud)

正确:

class MyTest extends PHPUnit_Framework_TestCase
{

    public function testThis()
    {
        $mock = $this->getMock('MyClass');
        $mock->expects($this->at(0))
             ->method('exists')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue(true));

        $mock->expects($this->at(1))
             ->method('find')
             ->with($this->equalTo('foo'))
             ->will($this->returnValue('foo'));

        $mock->expects($this->at(2))
             ->method('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertEquals('foo', $mock->find('foo'));
        $this->assertFalse($mock->exists("bar"));
    }

}
Run Code Online (Sandbox Code Playgroud)

  • 同意,如果at()索引在每个方法的基础上增加,那么间谍方法调用会更容易和更有用. (10认同)
  • 是的,但我认为这是PHPUnit中的一个错误.文档说:返回一个匹配器,该匹配器在给定的$ index处调用它所评估的方法时匹配. (5认同)

yvo*_*yer 17

仅供参考,我不确定它是否相关,但我遇到了同样的事情,但没有使用$this->at()方法,对我来说这是$this->never()方法.

这引起了错误

$mock->expects($this->never())
    ->method('exists')
    ->with('arg');
Run Code Online (Sandbox Code Playgroud)

这修复了错误

$mock->expects($this->never())
    ->method('exists');  
Run Code Online (Sandbox Code Playgroud)

使用该$this->exactly(0)方法时它做了同样的事情.

希望这能有所帮助.

  • @SilviuG,因为永远不应该调用该方法,所以对于with参数的期望永远不会发生.因此,由于配置的方法期望未发生但配置为发生(因为with),因此错误是触发器.希望它有意义.我同意这个错误的消息有点奇怪. (3认同)

小智 5

尝试$this->at(1)改为$this->at(2)