PHPUnit:模拟__get()导致“__ get()必须正好接受1个参数......”

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PHPUnit:模拟__get()导致“__ get()必须正好接受1个参数......”相关的知识,希望对你有一定的参考价值。

我在模拟重载的__get($ index)方法时遇到了问题。要模拟的类的代码和使用它的被测系统如下:

<?php
class ToBeMocked
{
    protected $vars = array();

    public function __get($index)
    {
        if (isset($this->vars[$index])) {
            return $this->vars[$index];
        } else {
            return NULL;
        }
    }
}

class SUTclass
{
    protected $mocky;

    public function __construct(ToBeMocked $mocky)
    {
        $this->mocky = $mocky;
    }

    public function getSnack()
    {
        return $this->mocky->snack;
    }
}

测试看起来如下:

<?php    
class GetSnackTest extends PHPUnit_Framework_TestCase
{
    protected $stub;
    protected $sut;

    public function setUp()
    {
       $mock = $this->getMockBuilder('ToBeMocked')
                     ->setMethods(array('__get')
                     ->getMock();

       $sut = new SUTclass($mock);
    }

    /**
     * @test
     */
    public function shouldReturnSnickers()
    {
        $this->mock->expects($this->once())
                   ->method('__get')
                   ->will($this->returnValue('snickers');

        $this->assertEquals('snickers', $this->sut->getSnack());
    }
}

真正的代码有点复杂,虽然不是很多,在其父类中有“getSnacks()”。但这个例子应该足够了。

问题是我在使用PHPUnit执行测试时遇到以下错误:

Fatal error: Method Mock_ToBeMocked_12345672f::__get() must take exactly 1 argument in /usr/share/php/PHPUnit/Framework/MockObject/Generator.php(231)

当我调试时,我甚至无法达到测试方法。它似乎在设置模拟对象时中断。

有任何想法吗?

答案

您可以使用returnCallback而不是returnValue来尝试:

$this->mock->expects($this->once())
    ->method('__get')
    ->will($this->returnCallback(array($this, 'callbackMethod')));

然后将调用参数callbackMethod调用方法__get

您的回调方法可能类似于:

public function callbackMethod()
{
    return 'snickers';
}

见:http://www.phpunit.de/manual/3.5/en/test-doubles.html#test-doubles.stubs.examples.StubTest5.php

另一答案

查看模拟魔法__get。可能你从另一个中调用另一个__get方法而没有正确模拟对象。

另一答案

__get()接受一个参数,所以你需要提供一个模拟:

/**
 * @test
 */
public function shouldReturnSnickers()
{
    $this->mock->expects($this->once())
               ->method('__get')
               ->with($this->equalTo('snack'))
               ->will($this->returnValue('snickers'));

    $this->assertEquals('snickers', $this->sut->getSnack());
}

with()方法为PHPUnit中的mocked方法设置参数。您可以在Test Doubles部分找到更多详细信息。

另一答案

withAnyParameters()方法可以帮到你,这个工作正确:

$this->mock -> expects($this -> once())  
    -> method('__get') -> withAnyParameters()
    -> will($this -> returnValue('snikers'));

以上是关于PHPUnit:模拟__get()导致“__ get()必须正好接受1个参数......”的主要内容,如果未能解决你的问题,请参考以下文章

(实用篇)浅谈PHP拦截器之__set()与__get()的理解与使用方法

python基础学习1-描述符

python类(资料+疑惑)

Python魔法方法(20):__ge__(self, other)方法

是否有可能使用 PHPUnit 模拟对象来调用一个神奇的 __call() 方法?

使用 PHPUnit 模拟 PDO 对象