Des mocks avec Prophecy

Publié le 27 octobre 2022 par Mathieu De Gracia
Couverture de l'article Des mocks avec Prophecy

Chez Laravel-France nous aimons écrire des tests et comme beaucoup de développeurs Laravel nous utilisons quotidiennement le couple PHPunit / Mockery.

Mockery a beau être la solution plébiscitée par PHPunit, il n'est pourtant pas le seul package existant permettant de créer des doublures (aka mock), Il existe des alternatives tout aussi robustes à notre disposition, c'est le cas du package que nous allons découvrir aujourd’hui : Prophecy.

phpspec/prophecy se décrit comme une solution “dogmatique” permettant de créer des puissants et flexibles mock dans vos tests.

Nous allons voir ce que le package propose et comment l'utiliser conjointement avec PHPunit.

Installation

Prophecy nécessite au minimum une version 7.2 de PHP et s'installe depuis composer :

1composer require phpspec/prophecy --dev

Une fois installé, le package est directement disponible dans vos tests, aucune configuration supplémentaire de PHPunit n'est nécessaire.

Utilisations basiques

Pour commencer, nous allons créer une nouvelle prophétie de l'objet que nous souhaitons "mocker", dans notre cas une class BarService.

1$prophet = new \Prophecy\Prophet();
2 
3$prophecy = $prophet->prophesize(BarService::class);

Nous devons ensuite manipuler cette instance de $prophecy pour configurer le comportement de notre futur mock.

Par exemple, déterminons ce que doit retourner la méthode bar du BarService en fonction des arguments que le mock recevra :

1$prophecy->bar('a')->willReturn('aaa');
2$prophecy->bar('b')->willReturn('bbb');

Si la méthode bar reçoit un argument 'a' : retourner 'aaa'

Une fois notre prophecy correctement configuré, la méthode reveal permet d'appliquer les différentes contraintes et d'obtenir la doublure !

1$barService = $prophecy->reveal();
2 
3$barService->bar('a'); // aaa
4$barService->bar('b'); // bbb
5$barService->bar('c'); // null
6$barService->bar(); // null

Avec Prophecy, il n'est nullement nécessaire de configurer tous les cas d'usage, utiliser la méthode bar de notre doublure avec un argument inattendu retournera NULL !

Des arguments

Notre précédent exemple était simple mais souffre d'une certaine rigidité, pour gagner en souplesse Prophecy dispose d'une class Argument permettant de configurer le comportement de vos doublures de manière bien plus dynamique, toujours basé sur les arguments que recevront les méthodes !

1use Prophecy\Argument;
2use Prophecy\Prophet;
3 
4$prophet = new Prophet();
5 
6$prophecy = $prophet->prophesize(BarService::class);
7 
8$prophecy->bar(Argument::type('string'))->will(function ($arguments) {
9 return true;
10});
11 
12$prophecy->bar(Argument::type('integer'))->will(function ($arguments) {
13 return false;
14});

Si la méthode bar reçoit un string : retourner 'true'

Cette class Argument contient bien d'autres méthode pour configurer vos doublures : is, exact, in, notIn ... Vous trouverez toutes ces alternatives dans le fichier Prophecy\Argument.php.

1$barService = $prophecy->reveal();
2 
3$barService->bar('a'); // true
4$barService->bar(1); // false
5$barService->bar(false); // null
6$barService->bar(); // null

L'une des forces de Prophecy est sa grande modularité, vous pouvez facilement créer votre propre class Argument en implémentant le contratTokenInterface.

Vous pourrez ainsi créer des arguments relatifs à votre métier et réutilisable dans plusieurs tests !

Des prédictions

Pour finir, Prophecy propose de vérifier l’accès aux méthodes de votre doublure avec des prédictions.

1$prophet = new Prophecy\Prophet();
2 
3$prophecy = $prophet->prophesize(BarService::class);
4 
5$prophecy->bar()->shouldBeCalled();
6$prophecy->bar('a')->shouldNotBeCalled();
7$prophecy->bar('b')->shouldBeCalledTimes(count: 3);

Il sera ensuite nécessaire de vérifier ces prédictions en appelant la méthode checkPredictions.

1$prophet->checkPredictions();

Allez plus loin

Bien que moins populaire que Mockery, Prophecy reste une solution alternative intéressante pour créer vos doublures en offrant sa propre vision, un peu différente, de ce que doit être un "mock" .

Vous pouvez retrouver toutes les informations de ce paquet sur son dépôt Github.

Mathieu De Gracia avatar
Mathieu De Gracia
Des fois, mon chat code à ma place 🐱

A lire

Autres articles de la même catégorie