PHPUnit“Mocked方法不存在”。当使用$ mock->期望($ this-> at(...))

时间:2010-07-29 22:34:45

标签: php unit-testing mocking phpunit

我遇到了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));
    }

    ...
}

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

Expectation failed for method name is equal to <string:exists> when invoked at sequence index 1.
Mocked method does not exist.

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

有没有人遇到过这个?

谢谢!

7 个答案:

答案 0 :(得分:42)

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

示例:

class MyClass {

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

    public function find($foo) {
        return $foo;
    }
}

不正确:

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"));
    }

}

正确:

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"));
    }

}

答案 1 :(得分:16)

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

这引发了错误

$mock->expects($this->never())
    ->method('exists')
    ->with('arg');

修复了错误

$mock->expects($this->never())
    ->method('exists');  

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

希望这有助于某人。

答案 2 :(得分:5)

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

答案 3 :(得分:3)

这是PHPUnit错误消息的一个不幸的措辞。

仔细检查您的通话顺序,例如@ rr的回答提及。

就我而言,就我自己的代码而言,我应该分别使用at(0)at(1),但直到我使用at(2)和{{1}而是它的工作原理。 (我在CakePHP中使用会话模拟。)

检查订单的最佳方法是“进入”被调用的方法并检查传递的内容。你可以这样做:

at(3)

答案 4 :(得分:1)

据我所知,从演示代码应该工作。我生成了一个工作示例,以防您运行较旧的PHPUnit版本,并希望检查它是否适用于您。

如果没有帮助,也许你可以提供更多(最好的可执行代码)代码? :)

<?php

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('exists')
             ->with($this->equalTo('bar'))
             ->will($this->returnValue(false));

        $this->assertTrue($mock->exists("foo"));
        $this->assertFalse($mock->exists("bar"));
    }

}

class MyClass {

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

印刷

phpunit MyTest.php
PHPUnit 3.4.15 by Sebastian Bergmann.

.

Time: 0 seconds, Memory: 4.25Mb

OK (1 test, 3 assertions)

答案 5 :(得分:0)

您确定在测试中包含了MyClass吗?在没有包含它的情况下模拟类/接口时,我遇到了一些未定义的方法错误。

答案 6 :(得分:0)

可能不是什么时候提出问题的,但是今天documentation明确规定了应如何使用at,我引用

  

注意
  at()匹配器的$ index参数引用给定模拟对象的所有方法调用中从零开始的索引。使用此匹配器时请格外小心,因为它可能导致脆弱的测试,而这些测试与特定的实现细节过于紧密地联系在一起。