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


85

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

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

動作しません。$callOriginalConstructorfalseに設定されていても、コンストラクター引数について文句を言います。

コンストラクターにはオブジェクトが1つしかなく、それは依存性注入です。ですから、デザインに問題はないと思います。

回答:


139

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

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

詳細については、PHPUnitのドキュメントの「テストダブル」のセクションを参照してください。

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


これは私にとって素晴らしいことです。ただし、例10.3である必要があります。投稿を編集しようとしましたが、編集が短すぎるためにキックバックしました。
マシュー

@Lytithwynに感謝します。答えを更新しました。
dave1010 2012年

42

どうぞ:

    // 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);

これはほとんど私が欲しいもののようです。モックするクラスと$ callMockConstructorのみを使用してgetMockを呼び出したいと思います。どうやって?このようなもの:$ this-> getMock($ classToMock、$ callMockConstructor)。私が考えることができる唯一のことは、PHPUnitのソースに移動し、それをdefault = falseに変更することです。
Gutzofter 2010

1
testcase.phpのデフォルトをfalseに変更しました。デフォルトではfalseに設定されていると思います。コンストラクターを
あざけるの

素晴らしい答え。私が探していたもの
Hades

4

補遺として、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);

の場合functionCallFromConstructprotectedsetMethods()保護されたメソッドがモックされるように特に使用する必要があることに注意してください。例:

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

setMethods()expect()呼び出す前に呼び出す必要があります。個人的に、私は後にこのをチェーンdisableOriginalConstructor()が、前にgetMock()


これがコードの臭いであるかどうかはわかりませんが、これは私にとってはうまくいきました。ありがとうございました。
devbanana

1

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


1

または、getMockにパラメーターを追加して、デフォルトのコンストラクターが呼び出されないようにすることもできます。

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

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


1

この質問は少し古いですが、新しい訪問者の場合は、createMockメソッド(以前createTestDoubleはv5.4.0で呼び出されて導入された)を使用して行うことができます。

$mock = $this->createMock($className);

PHPUnit\Framework\TestCase(のphpunit/src/framework/TestCase.php)クラスから抽出された以下のコードでわかるように、基本的に、元のコンストラクターを呼び出さずにモックオブジェクトを作成します

/** PHPUnit\Framework\TestCase::createMock method */
protected function createMock(string $originalClassName): MockObject
{
    return $this->getMockBuilder($originalClassName)
                ->disableOriginalConstructor()
                ->disableOriginalClone()
                ->disableArgumentCloning()
                ->disallowMockingUnknownTypes()
                ->getMock();
}

0

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

  1. モックに問題があるオブジェクトに依存関係としてモックオブジェクトを挿入します
  2. 親コンストラクターを呼び出さない、呼び出そうとしているクラスを拡張するテストクラスを作成します
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.