2013-08-16 8 views
20

私はメソッドを呼び出してレスポンスをアサートするかなり標準的なユニットテストを作成しようとしていますが、テストしているメソッドは同じクラス少し重い持ち上げをします。モックを必要とする他のクラスメソッドを呼び出すphpunitのテストメソッド

私はその1つのメソッドを模擬したいが、私はそのままテストしているメソッドを実行し、他のメソッドの呼び出しから返された模擬値でのみ実行します。

私はこの例をできるだけシンプルにすることを愚かにしました。

class MyClass 
{ 

    // I want to test this method, but mock the handleValue method to always return a set value. 

    public function testMethod($arg) 
    { 

     $value = $arg->getValue(); 

     $this->handleValue($value); 

    } 


    // This method needs to be mocked to always return a set value. 

    public function handleValue($value) 
    { 

     // Do a bunch of stuff... 
     $value += 20; 

     return $value; 

    } 

} 

私はテストを書くことを試みました。

class MyClassTest extends \PHPUnit_Framework_TestCase 
{ 


    public function testTheTestMethod() 
    { 

     // mock the object that is passed in as an arg 
     $arg = $this->getMockBuilder('SomeEntity')->getMock(); 
     $arg->expects($this->any()) 
      ->method('getValue') 
      ->will($this->returnValue(10)); 

     // test handle document() 
     $myClass = new MyClass(); 

     $result = $myClass->testMethod($arg); 

     // assert result is the correct 
     $this->assertEquals($result, 50); 

    } 

} 

私は、MyClassのオブジェクトをからかっ試してみましたが、私はそれを行うとのtestMethodを呼び出すときは、常にnullを返します。私は1つの方法を模擬する方法が必要ですが、オブジェクトの残りの部分はそのまま残しておきます。

答えて

21

あなたがテストしているクラスを模擬し、模擬したいメソッドを指定することができます。

$mock = $this->getMockBuilder('MyClass') 
    ->setMethods(array('handleValue')) 
    ->getMock(); 

$mock->expects($this->once()) 
    ->method('handleValue') 
    ->will($this->returnValue(23)) //Whatever value you want to return 

しかし、IMOこれはあなたのテストのための最高のアイデアではありません。このようなテストでは、リファクタリングがずっと難しくなります。あなたは、クラスが持つと思われる動作ではなく、クラスの実装を指定しています。 handleValueがテストを困難にする複雑な作業をたくさん行っている場合は、ロジックを別のクラスに移動し、クラスに注入することを検討してください。その後、そのクラスのモックを作成してtestMethodに渡すことができます。 handleValueがその動作に適応する必要がある場合、MyClassをさらに拡張可能にするという追加の利点があります。

http://www.oodesign.com/strategy-pattern.html

は、一般的なルールとして、あなたがテストしているシステムを模擬べきではありません。

+0

いい回答です、ありがとうございます。 – greg

+1

メソッド 'handleValue'が別のクラスにある場合はどうすればいいですか? – Somar

+0

良い答え、私はテストメソッドと模擬メソッドの間で部分モックを使用する必要があるときにテスト依存関係を適用します(ロジックをリファクタリングすることが不可能な場合) – kurroman

9

あなたはsetMethods()と嘲笑するためにどの方法(部分モック)を指定することができます。

// Let's do a `partial mock` of the object. By passing in an array of methods to `setMethods` 
// we are telling PHPUnit to only mock the methods we specify, in this case `handleValue()`. 

$csc = $this->getMockBuilder('Lightmaker\CloudSearchBundle\Controller\CloudSearchController') 
      ->setConstructorArgs($constructor) 
      ->setMethods(array('handleValue')) 
      ->getMock(); 

// Tell the `handleValue` method to return 'bla' 
$csc->expects($this->any()) 
    ->method('handleValue') 
    ->with('bla'); 

をあるとして、あなたがsetMethods()を与える配列に指定されていないクラスの他のメソッドが実行されます。 を使用しない場合setMethods具体的に設定しない限り、すべてのメソッドはNULLを返します。

関連する問題