web-dev-qa-db-ja.com

phpunitはモックのコンストラクタ引数を回避します

Phpunitがモックオブジェクトのコンストラクタを呼び出す必要を回避する方法は何ですか?そうでない場合、コンストラクター引数としてモックオブジェクトが必要になります。そのための別のオブジェクトが必要になります。APIは次のようになります。

getMock($className, $methods = array(), array $arguments = array(),
        $mockClassName = '', $callOriginalConstructor = TRUE,
        $callOriginalClone = TRUE, $callAutoload = TRUE)

動作しません。 $callOriginalConstructorがfalseに設定されている場合でも、コンストラクター引数についてはまだ文句を言います。

コンストラクターにはオブジェクトが1つしかなく、これは依存関係の注入です。だから私はそこに設計上の問題があるとは思わない。

80
Koen

getMockBuilderの代わりにgetMockを使用できます:

$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

PHPUnitのドキュメント"Test Doubles" のセクションを参照してください。

これを行うことはできますが、必要のない方がはるかに優れています。コードをリファクタリングして、具体的なクラス(コンストラクターを含む)を挿入する必要がなく、インターフェースにのみ依存するようにすることができます。これは、コンストラクターの動作を変更するようPHPUnitに指示することなく、インターフェイスをモックまたはスタブできることを意味します。

136
dave1010

どうぞ:

    // Get a Mock Soap Client object to work with.
    $classToMock = 'SoapClient';
    $methodsToMock = array('__getFunctions');
    $mockConstructorParams = array('fake wsdl url', array());
    $mockClassName = 'MyMockSoapClient';
    $callMockConstructor = false;
    $mockSoapClient = $this->getMock($classToMock,
                                     $methodsToMock,
                                     $mockConstructorParams,
                                     $mockClassName,
                                     $callMockConstructor);
42
Matthew Purdon

補足として、expects()呼び出しをモックされたオブジェクトにアタッチし、コンストラクターを呼び出したいと思いました。 PHPUnit 3.7.14では、disableOriginalConstructor()を呼び出したときに返されるオブジェクトは文字通りオブジェクトです。

_// Use a trick to create a new object of a class
// without invoking its constructor.
$object = unserialize(
sprintf('O:%d:"%s":0:{}', strlen($className), $className)
_

残念ながら、PHP 5.4には、使用していない新しいオプションがあります。

ReflectionClass :: newInstanceWithoutConstructor

これは利用できなかったため、手動でクラスを反映し、コンストラクターを呼び出す必要がありました。

_$mock = $this->getMockBuilder('class_name')
    ->disableOriginalConstructor()
    ->getMock();

$mock->expect($this->once())
    ->method('functionCallFromConstructor')
    ->with($this->equalTo('someValue'));

$reflectedClass = new ReflectionClass('class_name');
$constructor = $reflectedClass->getConstructor();
$constructor->invoke($mock);
_

functionCallFromConstructprotectedである場合、特にsetMethods()を使用して、保護されたメソッドがモックされるようにする必要があります。例:

_    $mock->setMethods(array('functionCallFromConstructor'));
_

setMethods()は、expect()呼び出しの前に呼び出す必要があります。個人的には、これをdisableOriginalConstructor()の後、getMock()の前に連結します。

3
Steve Tauber

おそらく、コンストラクター引数として渡すスタブを作成する必要があります。その後、モックオブジェクトのチェーンを解除できます。

1
Glenn Moss

または、パラメータを getMock に追加して、デフォルトコンストラクターの呼び出しを防ぐこともできます。

$mock = $this->getMock(class_name, methods = array(), args = array(), 
        mockClassName = '', callOriginalConstructor = FALSE);

それでも、dave1010の答えはより良く見えると思います。これは完全を期すためです。

1
Hans Wouters

PHPUnitは、モックされたオブジェクトでコンストラクターを呼び出すように設計されています。これを防ぐには、次のいずれかを行う必要があります。

  1. モックに問題があるオブジェクトにモックオブジェクトを依存関係として挿入する
  2. 親コンストラクターを呼び出さない、呼び出そうとしているクラスを拡張するテストクラスを作成する
0
silfreed