假设我有一个类包含一个使用类型提示的函数:
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
单元测试此功能?
答案 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