PHPUnit“模拟的方法不存在."当使用 $mock->expects($this->at(...))

2022-01-25 00:00:00 mocking unit-testing php phpunit

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

I've run into a strange issue with PHPUnit mock objects. I have a method that should be called twice, so I'm using the "at" matcher. This works for the first time the method is called, but for some reason, the second time it's called, I get "Mocked method does not exist.". I've used the "at" matcher before and have never run into this.

我的代码如下所示:

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

    ...
}

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

When I run the test, I get:

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

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

If I remove the second matcher, I do not get the error.

以前有人遇到过这种情况吗?

Has anyone run into this before?

谢谢!

推荐答案

问题最终在于我如何理解at"匹配器的工作原理.另外,我的示例在我的单元测试中并没有逐字记录.我认为at"匹配器计数器是在每个查询的基础上工作的,它实际上是在每个对象实例的基础上工作的.

The issue ended up being with how I understood the "at" matcher to work. Also, my example was not verbatim how it is in my unit test. I thought the "at" matcher counter worked on a per query basis, where it really works on a per object instance basis.

例子:

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

}

相关文章