PHPUnit MockObjectsがパラメーターに基づいて異なる値を返すようにするにはどうすればよいですか?


141

'return value'引数に関係なく返すPHPUnitモックオブジェクトを持っています。

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
     ->method('methodToMock')
     ->will($this->returnValue('return value'));

私ができることは、モックメソッドに渡された引数に基づいて異なる値を返すことです。私は次のようなことを試しました:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('one'))
     ->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('two'))
     ->will($this->returnValue('method called with argument "two"'));

しかし、これは、モックが引数'two'で呼び出されない場合にPHPUnitが文句を言うのでmethodToMock('two')、の定義が最初の定義を上書きすると仮定します。

だから私の質問は:PHPUnitモックオブジェクトを取得して、その引数に基づいて異なる値を返す方法はありますか?もしそうなら、どのように?

回答:


125

コールバックを使用します。例(PHPUnitのドキュメントから直接):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

callback()で必要な処理を行い、必要に応じて$ argsに基づいて結果を返します。


2
ドキュメントへのリンクを提供できますか?「グーグル」では見つけられないようです
クリスエリクソン、

6
配列などを渡すことで、メソッドをコールバックとして使用できることに注意してください$this->returnCallback(array('MyClassTest','myCallback'))
Patrick Fisher、

1
クロージャを直接渡すことも可能である必要があります
Ocramius 2012

7
これはまれなケースでのみ使用する必要があります。カスタムロジックをコールバックで記述する必要がないため、代わりにreturnValueMapを使用することを勧めします。
Herman J. Radtke III 2012

1
感謝しきれません。また、PHPバージョン> 5.4では、匿名関数をコールバックとして使用できます。$this->returnCallback(function() { // ... })
bmorenate 2015年

110

最新のphpUnitドキュメントから:「スタブ化されたメソッドは、事前定義された引数のリストに応じて異なる値を返す場合があります。returnValueMap()を使用して、引数を対応する戻り値に関連付けるマップを作成できます。」

$mock->expects($this->any())
    ->method('getConfigValue')
    ->will(
        $this->returnValueMap(
            array(
                array('firstparam', 'secondparam', 'retval'),
                array('modes', 'foo', array('Array', 'of', 'modes'))
            )
        )
    );

3
投稿のリンクは古く、正しいものはここにあります:returnValueMap()
hejdav

49

私は同様の問題を抱えていました(わずかに異なりますが...引数に基づいて異なる戻り値は必要ありませんでしたが、2つの引数セットが同じ関数に渡されることを確認するためにテストする必要がありました)。私はこのようなものを偶然見つけました:

$mock = $this->getMock();
$mock->expects($this->at(0))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

$mock->expects($this->at(1))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

foo()への2つの呼び出しの順序がわかっている必要があるため、完全ではありませんが、実際には、これはそれほど悪くないでしょう。


28

おそらくコールバックをOOP方式で実行したいと思うでしょう。

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnAction()
    {
        $object = $this->getMock('class_name', array('method_to_mock'));
        $object->expects($this->any())
            ->method('method_to_mock')
            ->will($this->returnCallback(array($this, 'returnCallback'));

        $object->returnAction('param1');
        // assert what param1 should return here

        $object->returnAction('param2');
        // assert what param2 should return here
    }

    public function returnCallback()
    {
        $args = func_get_args();

        // process $args[0] here and return the data you want to mock
        return 'The parameter was ' . $args[0];
    }
}
?>

16

それは正確にはあなたが尋ねるものではありませんが、いくつかのケースではそれが助けになります:

$mock->expects( $this->any() ) )
 ->method( 'methodToMock' )
 ->will( $this->onConsecutiveCalls( 'one', 'two' ) );

onConsecutiveCalls-指定された順序で値のリストを返します


4

2つのレベルの配列を渡します。各要素は次の配列です。

  • 最初はメソッドのパラメーターであり、最小値は戻り値です。

例:

->willReturnMap([
    ['firstArg', 'secondArg', 'returnValue']
])

2

次のように引数を返すこともできます。

$stub = $this->getMock(
  'SomeClass', array('doSomething')
);

$stub->expects($this->any())
     ->method('doSomething')
     ->will($this->returnArgument(0));

Mockingのドキュメントを見るとわかるように、このメソッドをreturnValue($index)使用すると、指定した引数を返すことができます。


0

こんな意味ですか?

public function TestSomeCondition($condition){
  $mockObj = $this->getMockObject();
  $mockObj->setReturnValue('yourMethod',$condition);
}

PHPUnitではなく、SimpleTestのコードだと思います。しかし、いいえ、それは私が達成したいものではありません。たとえば、指定された数の単語を返すモックオブジェクトがあるとします。私のモックメソッドは、1で呼び出された場合は「1」を返し、2で呼び出された場合は「2」を返す必要があります。$
Ben Dowling

0

私も同様に解決できなかった同様の問題がありました(PHPUnitについては驚くほど少ない情報しかありません)。私の場合、各テストを別々のテストにしました-既知の入力と既知の出力。全商品のジャックのモックオブジェクトを作成する必要がないことに気づきました。特定のテストには特定のオブジェクトだけが必要なので、テストを分離し、コードの個々の側面を個別にテストできます単位。これがあなたに当てはまるかどうかはわかりませんが、それはあなたがテストする必要があるものです。


残念ながら、それは私の状況ではうまくいきません。モックがテストしているメソッドに渡され、テストメソッドがモックされたメソッドを異なる引数で呼び出します。あなたが問題を解決できなかったことを知っていることは興味深いです。これはPHPUnitの制限である可能性があるようです。
ベンダウリング

-1
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');

    public function testBusiness()
    {
        /*
            onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
        */
        $this->BusinessMock ->method('getEmployees')
                                ->will($this->onConsecutiveCalls(
                                            $this->returnArgument(0),
                                            $this->returnValue('employee')                                      
                                            )
                                      );
        // first call

        $this->assertInstanceOf( //$this->returnArgument(0),
                'argument',
                $this->BusinessMock->getEmployees()
                );
       // second call


        $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
      //$this->returnValue('employee'),


    }

-2

試してください:

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));

この回答は元の質問には当てはまりませんが、私が抱えていた同様の問題について詳しく説明しています。特定のパラメーターセットが提供さていることを確認します。PHPUnitのwith()は複数の引数を受け入れます。各パラメーターに1つのマッチャーがあります。
TaZ、
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.