web-dev-qa-db-ja.com

型ヒントを使用する関数を単体テストする方法

次のような型ヒントを使用する関数を含むクラスがあるとします。

class Testable 
{
    function foo (Dependency $dependency) 
    {

    }
}

そして、私はこのコードを使用してこのクラスTestableをユニットテストしたいと思います:

$dependencyMock = $this->getMockBuilder('Dependency')
        ->disableOriginalConstructor()
        ->getMock();


$testable = new Testable($dependencyMock);

PHPUnitを使用して$ dependencyのスタブを作成し、このモック(上記のように)を使用してfoo関数を呼び出そうとすると、次のような致命的なエラーが発生します。

関数foo()に渡される引数1はDependencyのインスタンスでなければならず、Mock_Fooのインスタンスが指定されている必要があります

この関数をPHPUnitで単体テストし、$dependencyをスタブするにはどうすればよいですか?

37
user3009816

モックを使用する場合は完全な名前空間を使用してください。これにより、モカリー継承の問題が修正されます。

$dependencyMock = $this->getMockBuilder('\Some\Name\Space\Dependency')
    ->disableOriginalConstructor()
    ->getMock();
$testable = new Testable($dependencyMock);
43
Shakil

PHP 5.4+で完全な名前空間を使用する最も簡単な方法は、クラスの静的メソッドを使用することです。

SomeClass::class

OPの例では:

$dependencyMock = $this->getMockBuilder(Dependency::class)
    ->disableOriginalConstructor()
    ->getMock();
$testable = new Testable($dependencyMock);

これにより、IDEを使用したリファクタリングがはるかに簡単になります

19
Gaz_Edge

シャキルの答えの私の説明:

私も同じ問題を抱えていました。

Symfony2クックブックに従って、私はのモックを作成しました

\Doctrine\Common\Persistence\ObjectManager

そして私のサービスコンストラクタは:

use Doctrine\ORM\EntityManager;

/* ... */

public function __construct(EntityManager $oEm)
{
    $this->oEm = $oEm;
}

だから私はユニットテストを作成しました(symfony2クックブックに従って):

$entityManager = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager')
    ->disableOriginalConstructor()
    ->getMock();

$myService = new MyService($entityManager);

次に、エラーが発生しました:

Argument 1 passed to MyService::__construct() must be an instance of Doctrine\ORM\EntityManager, instance of Mock_ObjectManager_f4068b7f given

EntityManagerのインスタンスではなくモックインスタンスがコンストラクターに渡されたため、最初にその型ヒントは単体テストと互換性がありませんでした。

したがって、いくつかの調査の後、クラスMock_ObjectManager_f4068b7fは実際にはモックのクラスを拡張する動的クラス(私の場合はDoctrine\ORM\EntityManager)なので、型のヒントは問題ではなく、うまく機能します。

私の解決策は、\ Doctrine\Common\Persistence\ObjectManagerの代わりにDoctrine\ORM\EntityManagerのモックを作成することでした:

$entityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
    ->disableOriginalConstructor()
    ->getMock();

$myService = new MyService($entityManager);

私はユニットテストから始めているので、私の説明が明らかになるかもしれません:p

5
Alcalyn