web-dev-qa-db-fra.com

Procédure de test unitaire des fonctions qui utilisent l'indication de type

Disons que j'ai une classe qui contient une fonction qui utilise une indication de type comme celle-ci:

class Testable 
{
    function foo (Dependency $dependency) 
    {

    }
}

Et je veux tester cette classe Testable en utilisant ce code:

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


$testable = new Testable($dependencyMock);

Si j'utilise PHPUnit pour créer un stub de $ dependency et que j'essaye d'appeler la fonction foo en utilisant ce simulacre (comme ci-dessus), j'obtiendrai une erreur fatale qui dit:

L'argument 1 passé à la fonction foo () doit être une instance de Dependency, instance de Mock_Foo donnée

Comment puis-je tester cette fonction avec PHPUnit et encore stub $dependency?

37
user3009816

Utilisez un espace de noms complet lorsque vous utilisez la moquerie, cela résoudra le problème d'héritage de la moquerie.

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

Le moyen le plus simple d'utiliser un espace de noms complet dans PHP 5.4+ est avec la méthode statique de classe:

SomeClass::class

Donc, dans l'exemple du PO:

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

Cela rend le refactoring avec un IDE beaucoup plus facile

19
Gaz_Edge

Mon explication pour la réponse de Shakil:

J'ai eu le même problème.

Suite au livre de recettes symfony2, j'ai créé une maquette de

\Doctrine\Common\Persistence\ObjectManager

et mon constructeur de services était:

use Doctrine\ORM\EntityManager;

/* ... */

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

J'ai donc créé mon test unitaire (suivant le livre de recettes symfony2):

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

$myService = new MyService($entityManager);

Ensuite, j'ai eu l'erreur:

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

Premièrement, je pensais que ce type d'indication était incompatible avec les tests unitaires, car une instance fictive était passée au constructeur au lieu d'une instance d'EntityManager.

Donc, après quelques recherches, la classe Mock_ObjectManager_f4068b7f est en fait une classe dynamique étendant la classe de votre maquette (dans mon cas Doctrine\ORM\EntityManager), donc le type d'indication est pas de problème et fonctionne bien.

Ma solution a été de créer une maquette de Doctrine\ORM\EntityManager au lieu de \ Doctrine\Common\Persistence\ObjectManager:

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

$myService = new MyService($entityManager);

Je ne fais que commencer par les tests unitaires, vous pouvez donc trouver mon explication évidente: p

5
Alcalyn