我正在为我的助手编写一些测试。这是我第一次想用嘲弄对象做些什么。我正在使用默认的PHPUnit模拟框架。
我编写了一个函数来准备我的模拟对象:
private function getTestStub(){
$mockResult = array();
$mock = $this->getMock('My\Entity\Product');
$mock->expects($this->once())
->method('getId')
->will($this->returnValue(1));
$mock->expects($this->once())
->method('getName')
->will($this->returnValue('jan'));
$mock->expects($this->once())
->method('getWoonplaats')
->will($this->returnValue('Amsterdam'));
$mockResult[] = $mock;
return $mockResult;
}
现在,当我的测试使用此存根时,我收到以下错误:
Fatal error: Call to undefined method Mock_Product_129abca6::getId()
我在这里做错了什么?
答案 0 :(得分:4)
PHPUnit会查看您尝试通过reflection或get_class_methods
进行模拟的课程。
您模拟的类(如果存在)由模拟对象扩展。类似地,实现了接口。您可以在代码中see how this works。这是一堆代码生成的东西,如果你想看一看它的工作原理,一个好的起点是PHPUnit_Framework_MockObject_Generator::generate
。
如果没有看到你正在尝试模拟的课程,我会猜测你的getter是由__call
生成的“神奇”方法,如下所示:
<?php
namespace My\Entity;
class Product
{
private $data = array();
public function __call($method, $args)
{
$set_or_get = strtolower(substr($method, 0, 3));
$prop = strtolower(substr($method, 3));
if ('get' === $set_or_get) {
return isset($this->data[$prop]) ? $this->data[$prop] : null;
} elseif ('set' === $set_or_get && isset($args[0])) {
$this->data[$prop] = $args[0];
} else {
throw new \BadMethodCallException();
}
}
}
PHPUnit无法真正做到你想要的,因为你试图调用的方法实际上并不存在,并且魔法__call
不能按预期工作。要么是因为PHPUnit本身就使用了那个方法(你必须深入研究它)。要解决这个问题,您需要tell PHPUnit which methods you want to include in your mock。
// the second argument let's you define methods
$mock = $this->getMock('My\Entity\Product');
// try doing this instead
$mock = $this->getMock('My\Entity\Product', array('getId', 'getName', 'getWoonplaats'));
This question也有上述和解决方法的一些很好的例子。