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 に答える