URL: https://linuxfr.org/news/pest-soit-des-tests-unitaires Title: PEST soit des tests unitaires Authors: windu.2b Ysabeau, barmic, Yves Bourguignon et BAud Date: 2021-08-25T13:57:40+02:00 License: CC By-SA Tags: php, pest, tests et phpunit Score: 3 PEST est un nouveau framework en PHP, permettant de rédiger des tests unitaires. Basé sur le célèbre (pour ceux qui développent en PHP) PHUnit, PEST a pour lui d’être plus élégant et simple à utiliser, et apporte notamment une plus grande fluidité dans l’écriture des tests unitaires. Il a été créé par Nuno Maduro, membre de la core team de [Laravel](https://linuxfr.org/tags/laravel/public), en [sponsorware](https://github.com/sponsorware/docs). Depuis le printemps 2020, il est publié sous [licence MIT](https://github.com/pestphp/pest/blob/master/LICENSE.md). Il ne possède aucune filiation avec Laravel, on peut tout à fait s’en servir sans. Petit tour d’horizon ! _(tous les exemples de code de cette dépêche proviennent de la documentation officielle de PEST)_ ---- [Site officiel](https://pestphp.com/) [Dépôt officiel (github)](https://github.com/pestphp/pest) [Licence MIT](https://github.com/pestphp/pest/blob/master/LICENSE.md) [Nuno Maduro créateur du projet](https://twitter.com/enunomaduro) [PEST in practice (série de vidéos)](https://www.youtube.com/playlist?list=PLb4Xm6fDKP2o3F1uP9DM7MfTO7P0W_mmB) ---- Premiers tests ============== Pour commencer, voyons à quoi ressemble un test basique, avec PEST. ```php assertTrue(true); expect(true)->toBeTrue(); }); ``` Contrairement à PHPUnit, qui regroupe chaque test dans une méthode de classe, chaque test dans PEST consiste à appeler la fonction `test` en lui passant 2 paramètres : la description du test (texte libre) et une fonction anonyme (_Closure_) contenant le code du test proprement dit. Le tout dans un simple fichier PHP (pas de classe, pas de _namespace_, rien de tout ça n’est nécessaire). Comme PEST repose sur PHPUnit, on peut utiliser les méthodes `assertXXX` déjà existantes et connues de tous, à travers `$this` (qui est un objet de type `PHPUnit\Framework\TestCase`, ce qui montre que PEST est une surcouche à PHPUnit, avec du sucre syntaxique dedans). Mais on peut aussi utiliser les nouvelles méthodes `toBeXXX` mises à notre disposition par PEST, et dont on parlera plus loin. Si le test ci-dessus réussit, PEST affichera : ```php ✓ asserts true is true ``` À noter que la fonction `test` a une petite sœur : `it` (même signature). La seule différence est que cette dernière affichera ceci, si le test réussit : ```php ✓ it asserts true is true ``` Expectations ============ Bien que PEST puisse s’utiliser comme PHPUnit (ce qui permet doucement de basculer d’un framework à l’autre), on peut bien évidemment aller plus loin, en tirant profit de sa spécificité : les expectations. Concrètement, cela consiste en une méthode `expect`, à qui on passe la variable à tester, et toute une série de méthodes fluides (_fluent interfaces_) qui vont chacune vérifier que la variable respecte telle ou telle règle. Reprenons l’exemple du début : ```php assertTrue(true); // expectation expect(true)->toBe(true); }); ``` On voit que la méthode `toBe` vérifie que la valeur `true` (passée en paramètre de la fonction `expect`) est bien égale à `true`. Voyons maintenant un cas un peu plus poussé (et plus proche de ce qu’on peut être amené à écrire, dans la vraie vie) : ```php expect($user)->toBeInstanceOf(User::class); ``` Ici, la méthode `toBeInstanceOf` vérifie que la variable `$user` est bien de type `User`. On ne va pas lister ici la palanquée de méthodes `toBeXXX` qui existent : [la documentation est là pour ça](https://pestphp.com/docs/expectations#available-expectations), avec un exemple pour chacune d’elles. Rappelons toutefois qu’il est tout à fait possible de chaîner les appels de méthodes, pour tester plusieurs choses sur une même valeur. Exemple : ```php expect('{"name":"Nuno","credit":1000.00}') ->json() ->toHaveCount(2); ``` Higher Order Tests ------------------ Avec le chaînage des méthodes vient aussi une autre possibilité de PEST : pouvoir tester les valeurs au sein de la variable passée à la fonction `expect`. Ainsi, plutôt que de faire plusieurs appels à `expect` (ce qui reste tout à fait possible), comme suit : ```php expect($user->first_name)->toEqual('Nuno'); expect($user->last_name)->toEqual('Maduro'); expect($user->withTitle('Mr'))->toEqual('Mr Nuno Maduro'); ``` On peut tout à fait faire ceci : ```php expect($user) ->first_name->toEqual('Nuno') ->last_name->toEqual('Maduro') ->withTitle('Mr')->toEqual('Mr Nuno Maduro'); ``` Et là, on commence à toucher à ce qui rend PEST si attrayant : le chaînage est sans limite ! On peut tester toutes les données contenues à l’intérieur de la valeur passée en paramètre à `expect`, que ce soit les propriétés d’un objet, comme on vient de le voir, ou les différents éléments d’un tableau, comme ci-dessous : ```php expect(['name' => 'Nuno', 'companies' => ['Pest', 'Laravel']]) ->name->toEqual('Nuno') ->companies->toHaveCount(2)->each->toBeString ``` (notez l’usage de `each`, qui permet de boucler sur les sous-éléments du tableau) Comme dit précédemment, il n’y a pas de limite dans le chaînage, ni dans le parcours en profondeur d’un objet ou d’un tableau. Ainsi, il est tout à fait possible d’aller chercher les propriétés d’un objet, et de tester qu’elles répondent elles aussi à certains critères. Exemple : ```php expect($user) ->companies->first()->owner->toBeInstanceOf(User::class)->not->toEqual($user) ->name->toEqual('Nuno'); ``` Dans cet exemple, on comprend que l’objet `$user` a 2 propriétés testées : `companies` (qui semble renvoyer une liste d’objets), dont on vérifie que le `owner` du premier élément est bien un objet de type `User`, mais n’est pas `$user`. Et `name`, dont on vérifie la valeur. Ici, `name` se rapporte à `$user`, et non à `companies` : PEST est capable de revenir à l’objet initialement traité (celui passé en paramètre à `expect`). Et ce, sans limite ! ## Custom expectations La liste des expectations a beau être très grande, et de nouvelles méthodes apparaissent chaque semaine, il y a toujours un moment où il manque celle dont on a besoin, pour couvrir son cas particulier. Fort heureusement, PEST permet l’ajout de nouvelles méthodes, grâce à la méthode `extend()`. Exemple : ```php // tests/Pest.php expect()->extend('toBeWithinRange', function ($min, $max) { return $this->toBeGreaterThanOrEqual($min) ->toBeLessThanOrEqual($max); }); test('numeric ranges', function () { expect(100)->toBeWithinRange(90, 110); }); ```