2012-11-29 3 views
12

私は、すべてのオーバーライドされたメソッドのデフォルト値を使用してsetUpでモックインスタンスを作成しようとしていますが、いくつかの異なるテストでは、設定しなくても何をテストしているかによっていくつかのメソッドの戻り値を変更します。モック全体。これを行う方法はありますか?PHPUnit Mockを設定した後、そのメソッドを変更することはできますか?

これは私が試みたものですが、素朴なアプローチは機能しません。この方法では、依然として元の期待設定からの値が返されます。

まずセットアップ:異なるアサートする前に別の試験で

$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will($this->returnValue(true)); 

$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will($this->returnValue(false)); 

この質問への複製:PHPUnit Mock Change the expectations later、それ1は何の回答を得なかったし、私は新しい質問がもたらすかもしれないと思いました前の問題。

/** 
* @dataProvider methodValueProvider 
*/ 
public function testMethodReturnValues($method, $expected) { 
    // ... 
    $my_mock->expects($this->any()) 
      ->method($method) 
      ->will($this->returnValue($expected)); 
    // ... 
} 

public function methodValueProvider() { 
    return array(
    array('one_of_many_methods', true), 
    array('another_one_of_many', false) 
); 
} 

編集:これを行うには

+0

AFAIK残念ながら、phpunitではそのような可能性はありません。例えば、$ my_mock - > __ phpunit_hasMatchers()を使用することができますが、それはあなたが望むものではありません。もちろん、a) "at" matcherまたはb) "returnCallback"では、同じメソッドで異なる戻り値を設定できますが、呼び出しの順序に依存します。b)呼び出しパラメータ..しかし、あなたが探しているものではありません。私は何か新しいことを理解することを知らせます。 – Cyprian

+0

も参照してくださいhttp://stackoverflow.com/questions/5484602/mock-in-phpunit-multiple-configuration-of-the-same-method-with-different-argum/5484864#5484864 – bishop

答えて

3

一つの方法は、次のようdata provider、何かを使用するようになり申し訳ありませんが、私はあなたの質問を読み違えます。上記は明らかにあなたが探しているものではありません。

1

私はこれを試していないが、しかし、あなたはセットアップでモックを設定することができませんでした、その後、各テストで:

public function testMethodReturnsTrue 
{ 
    $this->my_mock->will($this->returnValue(true)); 
    $this->assertTrue(...); 
    ... 
} 

私がしようとしているように私は、これが機能するかどうかわかりません最初のモックが作成されたときではなく、テストでwill()メソッドを設定します。

5

同じメソッドを複数回使用する場合は、コード内で実行される適切なカウントで "at"宣言を使用する必要があります。このようにして、PHPUnitはあなたが意味するものを知り、expectation/assertionを適切に実行することができます。私は、これはあなたが探しているものだと思うが、私は誤解してるなら、私に知らせてください

public function testRunUsingAt() 
    { 
     $test = $this->getMock('Dummy'); 

     $test->expects($this->at(0)) 
      ->method('run') 
      ->with('f', 'o', 'o') 
      ->will($this->returnValue('first')); 

     $test->expects($this->at(1)) 
      ->method('run') 
      ->with('b', 'a', 'r') 
      ->will($this->returnValue('second')); 

     $test->expects($this->at(2)) 
      ->method('run') 
      ->with('l', 'o', 'l') 
      ->will($this->returnValue('third')); 

     $this->assertEquals($test->run('f', 'o', 'o'), 'first'); 
     $this->assertEquals($test->run('b', 'a', 'r'), 'second'); 
     $this->assertEquals($test->run('l', 'o', 'l'), 'third'); 
    } 

は、以下の方法「実行」は、数回使用される一般的な例です。

何かを嘲笑することで、何度でもそれを模擬することができますが、設定と同じ名前でモックしたくはありません。セットアップに。異なるシナリオで同様のメソッドをテストする必要がある場合は、各テストごとにそれを模擬します。セットアップでモックを1つ作成することもできますが、1つのテストでは、グローバル名ではなく、個々のテスト内で類似したアイテムの別のモックを使用します。あなたは、このラムダコールバックを使用して行うことができ

+5

私はこれが受け入れられるべきだと思いますしかし、at()に使用するインデックスは、その特定のメソッドへの呼び出し数ではなく、そのモックオブジェクトへの呼び出しの総数に基づいていることにも注意してください。したがって、同じオブジェクト上の他のメソッドに他の呼び出しが行われた場合は、それに応じてインデックスを増やす必要があります。 – Russ

3

$one_of_many_methods_return = true; 
$my_mock->expects($this->any()) 
     ->method('one_of_many_methods') 
     ->will(
      $this->returnCallback(
       function() use (&$one_of_many_methods_return) { 
        return $one_of_many_methods_return; 
       } 
      )   
     ); 
$this->assertTrue($my_mock->one_of_many_methods()); 

$one_of_many_methods_return = false; 

$this->assertFalse($my_mock->one_of_many_methods());  

use文で&に注意してください。

+0

テストメソッドがプロパティ( '$ this-> one_of_many_methods_return')を参照('&$ one_of_many_methods_return')よりも共有する方が簡単ですが、これは一回限りの値に便利です。 '$ this-> returnCallback([$ this、 'someMethod'])'のようにメソッドを直接使うこともできます。また、PHP <5.5では、匿名関数で '$ this'とプライベート/保護されたプロパティ/メソッドを使用することについて不満を持ちます。 – Warbo

1

mockedメソッドをオーバーライドしようとするのではなく、mockedオブジェクト自体をオーバーライドする方が簡単です。たとえば:

class ThingTest extends \PHPUnit_Framework_TestCase 
    public function setUp() 
    { 
     $this->initFoo(); 
     $this->initBar(); 
    } 

    public function testOne() 
    { 
     // Uses default [method => value] map for foo and bar 
     $this->assertSomething($this->thing->someMethod()); 
    } 

    public function testTwo() 
    { 
     // Override foo's map 
     $this->initFoo(['method1' => 'some other value']); 
     $this->assertSomethingElse($this->thing->someMethod()); 
    } 

    public function testThree() 
    { 
     // Override bar explicitly, so we can use 'once' 
     $this->initBar([]); 
     $this->bar->expects($this->once()) 
        ->method('method1'); 
     $this->thing->someOtherMethod(); 
    } 

    private function initFoo($methods = null) 
    { 
     $this->init('foo', 
        $this->getMock('Foo'), 
        is_null($methods)? ['method1' => 'default value 1'] 
            : $methods); 
    } 

    private function initBar($methods = null) 
    { 
     $this->init('bar', 
        $this->getMock('Bar'), 
        is_null($methods)? ['method1' => 'default value 1'] 
            : $methods); 
    } 

    private function init($name, $object, $methods) 
    { 
     $this->$name = $object; 
     foreach ($methods as $method => $value) { 
      $this->$name->expects($this->any()) 
         ->method($method) 
         ->will($this->returnValue($value)); 
     } 
     $this->thing = new Thing($this->foo, $this->bar); 
    } 
} 
0

あなたはまた、別のプロセスでテストを実行することができます。この例では

/** 
* @runTestsInSeparateProcesses b/c we change the return value of same expectation 
* @see http://stackoverflow.com/questions/13631855 
*/ 
class ThingTest extends \PHPUnit_Framework_TestCase 
{ 
    public function setUp() { 
     $this->config = Mockery::mock('alias:Config'); 
    } 

    public function test_thing_with_valid_config() { 
     $this->config_set('default', 'valid'); 
     $sut = new \Thing(); 
    } 

    /** 
    * @dataProvider provides_broken_configs 
    * @expectedException \RuntimeException 
    */ 
    public function test_thing_with_broken_config($default) { 
     $this->config_set('default', $default); 
     $sut = new \Thing(); 
    } 

    public function provides_broken_configs() { 
     return [ [ null ] ]; 
    } 

    protected function config_set($key, $value) { 
     $this->config->shouldReceive('get')->with($key)->andReturn($value); 
    } 
} 

を、私は嘲笑を使用することが起こるが、パターンは同じです。各テストには新しいメモリがそれぞれ実行されるため、以前に設定された期待値を「上書き」するという制限に遭遇することはありません。