Подтвердить что ты не робот

Как 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?

4b9b3361

Ответ 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