Injection automatique de dépendances simulées pour les tests
injected Trait
vous permet de créer facilement des classes avec toutes leurs dépendances simulées à des fins de test.
Le modèle suivant est très courant :
A
avec ses dépendances (objets de service) transmises via le constructeurA
, affirmant qu'elles sont appelées comme prévu. Une grande partie de la logique de test finit par être un passe-partout pour la construction d'un objet. injected Trait
vise à supprimer complètement ce passe-partout, vous permettant de vous concentrer sur ce qui compte : les tests eux-mêmes.
Utilisez composer
pour obtenir la dernière version (vous n'en aurez probablement besoin que pour le développement) :
$ composer require sellerlabs/ injected --dev
Supposons que nous développions une application Web et que nous souhaitions envoyer un e-mail aux utilisateurs lorsqu'ils s'inscrivent. Pour un exemple simple, supposons qu'un utilisateur soit entièrement défini par son adresse e-mail. Lorsqu'ils s'inscrivent, nous souhaitons naturellement leur envoyer un e-mail de remerciement. De plus, nous aimerions tester que les e-mails sont réellement envoyés sans réellement les envoyer .
Tout d'abord, définissons un service de messagerie :
class EmailService
{
public function email ( $ address , $ content )
{
// Send an email to $address with body $content
}
}
(Dans une application réelle, email
enverrait un e-mail -- nous ne nous préoccupons pas de la mise en œuvre ici, cependant !)
Définissons également un UserController
qui gère le processus d'inscription extrêmement simple :
class UserController
{
private $ service ;
public function __construct ( EmailService $ service )
{
$ this -> service = $ service ;
}
public function signUp ( $ emailAddress )
{
$ this -> service -> email ( $ emailAddress , ' Thanks for signing up! ' );
return $ emailAddress ;
}
}
Ici, nous fournissons la dépendance EmailService
via le constructeur et l'utilisons pendant notre processus d'inscription (incroyablement simple).
Pour tester cette classe, nous devrons faire l'une des deux choses suivantes :
EmailService
en utilisant quelque chose comme Mockery
et assurez-vous que email
est appelé avec les arguments attendus. injected Trait
vous permet d'atteindre sans douleur l'option 2. Jetons un coup d'oeil :
use SellerLabs injected injected Trait ;
/**
* Class injected Example
*
* // 1. These are helpful annotations for IDEs and language tools
* @property MockInterface $service
* @method UserController make()
*
* @author Benjamin Kovach <[email protected]>
*/
class injected Example extends PHPUnit_Framework_TestCase
{
// 2. Use our trait
use injected Trait;
// 3. Provide the name of the class to test
protected $ className = UserController::class;
public function testSignUp ()
{
// 4. Make a controller with mocked dependencies
$ controller = $ this -> make ();
$ address = ' [email protected] ' ;
// 5. We can access any mocked dependency of the class as a property
$ this -> service -> shouldReceive ( ' email ' )
-> withArgs (
[
$ address ,
' Thanks for signing up! '
]
);
$ result = $ controller -> signUp ( $ address );
$ this -> assertEquals ( $ address , $ result );
}
}
Chaque classe utilisant injected Trait
doit avoir la propriété $className
, qui est utilisée pour localiser la classe testée. injected Trait
fournit une seule méthode publique, make
, qui construit un objet de ce type, mais simule ses dépendances et les enregistre en tant que propriétés dans la classe de test elle-même.
Ainsi, dans testSignUp
, nous construisons le contrôleur en utilisant make()
, ce qui nous donne accès à un objet de type EmailService
simulé appelé $service
. En effet, il est défini de cette façon dans le constructeur du UserController
:
public function __construct ( EmailService $ service )
{
$ this -> service = $ service ;
}
Pendant la durée du scénario de test, la variable membre $service
est liée à ce EmailService
simulé, ce qui nous permet de faire des attentes sur ce qui se passe lorsque la méthode signUp
du contrôleur est appelée. Nous utilisons Mockery
afin de créer les objets simulés. Il y a quelques annotations dans le commentaire de classe, qui facilitent l'auto-complétion IDE pour ces classes puisque les propriétés fictives sont déclarées dynamiquement.
Cet exemple se trouve dans tests/ injected Example.php
. N'hésitez pas à fouiner !
L'impact de cette fonctionnalité peut sembler relativement faible, mais lorsque vous travaillez sur des applications volumineuses où les classes ont plusieurs dépendances, cela rend les tests beaucoup plus faciles.