PHPUnit “模拟方法不存在。”当使用 $mock->expects($this->at(...))
Posted
技术标签:
【中文标题】PHPUnit “模拟方法不存在。”当使用 $mock->expects($this->at(...))【英文标题】:PHPUnit "Mocked method does not exist." when using $mock->expects($this->at(...)) 【发布时间】:2011-03-23 00:05:24 【问题描述】:我遇到了一个关于 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.
如果我删除第二个匹配器,我不会收到错误消息。
以前有人遇到过这种情况吗?
谢谢!
【问题讨论】:
【参考方案1】:问题最终在于我如何理解“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"));
【讨论】:
是的,但我认为这是 PHPUnit 中的一个错误。文档说:返回一个匹配器,当它被评估的方法在给定的 $index 处被调用时匹配。 同意,另外,如果 at() 索引基于每个方法递增,那么监视方法调用会更容易和更有用。 看起来任何对期望的错误使用都会导致“模拟方法不存在”消息。很高兴知道。 这使得模拟多个方法几乎无法使用 今天它仍然这样工作,现在我用这篇文章修复了我的测试,我把帽子砸在地板上【参考方案2】:仅供参考,不确定它是否相关,但我遇到了同样的事情,但不是$this->at()
方法,对我来说是$this->never()
方法。
这引发了错误
$mock->expects($this->never())
->method('exists')
->with('arg');
这修复了错误
$mock->expects($this->never())
->method('exists');
在使用$this->exactly(0)
方法时,它做了同样的事情。
希望这对某人有所帮助。
【讨论】:
谢谢!这真的很有帮助,我遇到了同样的问题,我被卡住了(直到我读到你的评论)。 谢谢,这也解决了我的问题。但我真的不知道它为什么起作用。你能解释一下这件事吗? @SilviuG,由于永远不应该调用该方法,因此对 with 参数的期望永远不会发生。因此,由于该方法的配置期望没有发生但被配置为发生(因为 with),错误被触发。希望这是有道理的。我同意这个错误的消息有点奇怪。 谢谢!有完全相同的问题。【参考方案3】:尝试将$this->at(1)
更改为$this->at(2)
【讨论】:
为我工作。我打电话给:foo
一次,bar
foo 之后的方法 3 次。从 1 个固定问题开始 bar
期望。【参考方案4】:
这是 PHPUnit 错误消息的不幸措辞。
仔细检查您的通话顺序,例如@rr 的回答提及。
就我而言,据我所知,我应该分别使用at(0)
和at(1)
,但直到我使用at(2)
和at(3)
才起作用。 (我在 CakePHP 中使用会话模拟。)
检查顺序的最佳方法是“进入”被调用的方法并检查传递的内容。你可以这样做:
$cakePost = $this->getMock('CakePost');
$cakePost->expects($this->once())
->method('post')
->with(
// Add a line like this for each arg passed
$this->callback(function($arg)
debug("Here's what was passed: $arg");
)
);
【讨论】:
天哪,真烦人!谢谢你,由于这个问题,我真的在为单元测试而苦苦挣扎。【参考方案5】:据我从演示代码中可以看出,它应该工作。我制作了一个工作示例,以防您运行的是较旧的 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)
【讨论】:
【参考方案6】:你确定你的测试中包含了 MyClass 吗?在模拟类/接口而不包含它时,我遇到了一些未定义的方法错误。
【讨论】:
是的,第一个匹配器工作正常,就是头部刮刀【参考方案7】:可能不是在提出问题时,但是今天documentation 明确指定了应该如何使用 at 并且我引用了
注意 at() 匹配器的 $index 参数指的是索引,从零开始,在给定模拟对象的所有方法调用中。使用此匹配器时要小心,因为它可能会导致与特定实现细节过于紧密相关的脆弱测试。
【讨论】:
以上是关于PHPUnit “模拟方法不存在。”当使用 $mock->expects($this->at(...))的主要内容,如果未能解决你的问题,请参考以下文章
使用 wordpress 的 phpunit 上的 RecursiveDirectoryIterator 错误