PhpUnit模拟:函数未定义

时间:2013-12-08 17:02:29

标签: php mocking phpunit

我正在为我的助手编写一些测试。这是我第一次想用嘲弄对象做些什么。我正在使用默认的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()

我在这里做错了什么?

1 个答案:

答案 0 :(得分:4)

PHPUnit会查看您尝试通过reflectionget_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也有上述和解决方法的一些很好的例子。