Как unit test функции, которые используют тип hinting
Предположим, что у меня есть класс, который содержит функцию, которая использует тип hinting следующим образом:
class Testable
{
function foo (Dependency $dependency)
{
}
}
И я хочу unit test этот класс Testable
с помощью этого кода:
$dependencyMock = $this->getMockBuilder('Dependency')
->disableOriginalConstructor()
->getMock();
$testable = new Testable($dependencyMock);
Если я использую PHPUnit для создания заглушки зависимости $, а затем попытаюсь вызвать функцию foo
с помощью этого макета (например, выше), я получу фатальную ошибку, которая говорит:
Аргумент 1, переданный функции foo(), должен быть экземпляром Dependency, экземпляром Mock_Foo, заданным
Как я могу unit test выполнить эту функцию с помощью PHPUnit и еще заглушить $dependency
?
Ответы
Ответ 1
Используйте полное пространство имен, когда вы используете насмешку, он исправит проблему наследования смешения.
$dependencyMock = $this->getMockBuilder('\Some\Name\Space\Dependency')
->disableOriginalConstructor()
->getMock();
$testable = new Testable($dependencyMock);
Ответ 2
Самый простой способ использовать полное пространство имен в PHP 5. 4+ - использовать статический метод класса:
SomeClass::class
Так в примере с OP:
$dependencyMock = $this->getMockBuilder(Dependency::class)
->disableOriginalConstructor()
->getMock();
$testable = new Testable($dependencyMock);
Это значительно упрощает рефакторинг с IDE.
Ответ 3
Мое объяснение для ответа Шакиля:
У меня была та же проблема.
После кулинарной книги symfony2 я создал макет
\Doctrine\Common\Persistence\ObjectManager
и мой конструктор службы:
use Doctrine\ORM\EntityManager;
/* ... */
public function __construct(EntityManager $oEm)
{
$this->oEm = $oEm;
}
Итак, я создал свой unit test (после кулинарной книги 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
Сначала я, хотя этот тип намека несовместим с модульными тестами, потому что экземпляр mock был передан конструктору вместо экземпляра EntityManager.
Итак, после некоторых исследований класс Mock_ObjectManager_f4068b7f на самом деле является динамическим классом, расширяющим класс вашего макета (в моем случае Doctrine\ORM\EntityManager), поэтому тип намека не является проблемой и работает хорошо.
Моим решением было создать mock Doctrine\ORM\EntityManager вместо \Doctrine\Common\Persistence\ObjectManager:
$entityManager = $this->getMockBuilder('\Doctrine\ORM\EntityManager')
->disableOriginalConstructor()
->getMock();
$myService = new MyService($entityManager);
Я только начинаю с модульных тестов, поэтому вы можете найти явное объяснение: p