15

我在模拟重载的 __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)

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

有任何想法吗?

4

5 回答 5

2

__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 中的模拟方法设置参数。您可以在Test Doubles部分找到更多详细信息。

于 2014-09-13T16:15:43.283 回答
1

它在评论中有点隐藏,但@dfmuir 的回答让我走上了正轨。__get如果您使用回调,则模拟方法很简单。

$mock
    ->method('__get')
    ->willReturnCallback(function ($propertyName) {
        switch($propertyName) {
            case 'id':
                return 123123123123;
            case 'name':
                return 'Bob';
            case 'email':
                return 'bob@bob.com';
        }
    }
);

$this->assertEquals('bob@bob.com', $mock->email);
于 2021-02-07T12:40:13.813 回答
0

查看模拟的魔术方法__get。可能您从另一个未正确模拟的对象中再调用一个 __get 方法。

于 2015-10-01T10:01:55.013 回答
0

您在班级setUp方法中所做的事情GetSnackTest是不正确的。如果您希望__get执行该方法的代码(这将是您的测试的重点> 我想),您必须更改您在该方法中调用setMethodssetup方式。 这是完整的解释,但这里是相关部分:

传递包含方法名称的数组

您确定的方法:

都是存根,默认都返回null,很容易被覆盖

因此,您需要setMethods通过传递来调用null,或者通过传递包含一些方法(您真正想要存根的方法)的数组来调用,但不是 __get(因为您实际上希望执行该方法的代码)。

在该shouldReturnSnickers方法中,您将只想调用$this->assertEquals('snickers', $this->sut->getSnack());,而没有前面的行与expect部分。这将确保您的__get方法的代码实际执行和测试。

于 2020-03-02T13:15:27.427 回答
-2

withAnyParameters() 方法可以帮助你,这是正确的:

$this->mock -> expects($this -> once())  
    -> method('__get') -> withAnyParameters()
    -> will($this -> returnValue('snikers'));
于 2014-10-09T11:42:32.197 回答