如何单元测试使用类型提示的函数

时间:2013-12-07 21:18:50

标签: unit-testing symfony mocking phpunit type-hinting

假设我有一个类包含一个使用类型提示的函数:

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单元测试此功能?

3 个答案:

答案 0 :(得分:42)

使用模拟时使用完整命名空间,它将修复嘲弄继承问题。

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

答案 1 :(得分:16)

在PHP 5.5+中使用完整命名空间的最简单方法是使用类静态方法:

SomeClass::class

所以在OP的例子中:

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

这使得使用IDE进行重构更容易

答案 2 :(得分:5)

我对Shakil答案的解释:

我遇到了同样的问题。

在symfony2 cookbook之后,我创建了一个模拟

\Doctrine\Common\Persistence\ObjectManager

我的服务构造函数是:

use Doctrine\ORM\EntityManager;

/* ... */

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

所以我创建了我的单元测试(在symfony2 cookbook之后):

$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 实际上是一个动态类,它扩展了mock的类(在我的例子中是 Doctrine \ ORM \ EntityManager ),所以类型提示不是问题而且效果很好。

我的解决方案是创建一个模拟 Doctrine \ ORM \ EntityManager 而不是 \ Doctrine \ Common \ Persistence \ ObjectManager

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

$myService = new MyService($entityManager);

我刚开始进行单元测试,所以你可能会发现我的解释明显:p