On a essayé Jest … et on a adoré

Cette semaine, je voulais vous parler test unitaire front-end et plus particulièrement de Jest, le test-runner de Facebook
Globalement, il y a 3 frameworks majeurs de tests unitaires en Javascript : Jasmine, Mocha et Jest, le plus récent. Avant d’expliquer pourquoi il nous a convaincu, on va commencer par lister ce que doit faire un test runner et plus généralement une stack de test unitaire orienté front-end. En effet, la distinction est parfois floue entre test-runners, librairies d’assertions et de mocks.

1.Structurer les tests

Un test runner est un peu la pièce centrale de votre stack de test unitaire.Typiquement, il s’agit de construire des tests et de les regrouper par fonctionnalités dans des suites:

Ils le font à peu près tous bien. Que vous écriviez du Jasmine, du Jest ou du Mocha, ce sera sensiblement la même chose. Si vous intégrez des librairies tierces, vous pourrez écrire vos specs sous une forme plus proche du BDD ( avec CucumberJS) ou de Qunit (pour les nostalgiques de Jquery =) ) .

2.Ecrire des assertions

C’est à dire les vérifications à réaliser à proprement dit. Dans l’exemple précédent, on avait utilisé ‘expect’
Le choix d’une librairie d’assertion avec laquelle vous êtes à l’aise fera la différence sur le temps d’écriture des tests et la maintenance.
Certains test runners embarquent leur propres librairie d’assertions. C’est le cas de Jest et de Jasmine. Mocha nécessite ( ou justement permet suivant le point de vue) d’utiliser une librairie d’assertions tierce ( par exemple Chai).
Tester un booléen ou une chaîne de caractères, c’est relativement simple. Pouvoir tester convenablement le retour d’un promesse ou un résultat conditionnel peut être plus compliqué.
Aussi certaines librairies d’assertions permettent d’ajouter des messages d’erreurs personnalisé sur les assertions pour rendre plus lisibles les erreurs dans le rapport de test.
 Par exemple Chai permet d’écrire ceci :

Imaginez que vous ayez écrit plusieurs assertions consécutive sur des booléens au sein d’un même test. Sans annotations sur les assertions, son échec sera très probablement sous la forme d’un laconique message  » expected ‘false’ to be ‘true’.  » … Bon courage pour débugguer.

De ce point de vue là, expect de Jest ne le permet pas et bien souvent, on a du se rabattre sur assert ( inclus dans Node Js). Sur ce point là , il y a un débat.

3.Instancier des composants

Les frameworks récents utilisent le pattern composant : l’application est découpée sous forme de composants autonomes avec leurs templates HTML, style CSS et implémentation Javascript. Comment tester unitairement ces composants ?
Il vous faut un outil qui crée un contexte et une nouvelle instance isolée du composant pour chaque test. C’est ce qu’on appelle un « Test Bed » ( banc de test).
Le Test Bed est très lié au framework d’écriture et il vaut mieux choisir celui sponsorisé par le framework:
– pour Angular ce sera TestBed du module ‘@angular/core/testing’,
– pour Vue ce sera Mount & Shallow de ‘vue-test-utils’
– pour React ce sera renderer de ‘react-test-renderer’

4.Gérer les dépendances.

Que vous testiez un composant ou plus simplement une fonction en pure Javascript, vous aurez surement des appels à des services tiers (des requêtes HTTP par exemple), ou des dépendances à des variables globales diverses.
A mon sens 95% des difficultés liées à l’écriture de tests unitaires en Javascript sont concentrées sur ce point.
On voudra alors faire 3 choses :
– Exécuter nos tests sans avoir à importer les dépendances tierces: on veut les tester séparement, d’autant plus qu’elles sont susceptibles elles aussi d’être bugguées. Pour ça on va bouchonner.

– Valider les modalités d’appels des services externes. Pour ça, on va espionner.

– Tester le comportement de notre code en jouant sur les retours de ces dépendances : si la promesse de l’appel de mon service backend renvoit une erreur, mon service doit l’attraper.

Encore une fois, Jest & Jasmine ont fait le choix d’intégrer les espions et les bouchons alors que pour Mocha, il faut intégrer une librairie dédiée tierce (la plus connue je crois est Sinon).
La capacité d’une libraire à créer simplement des bouchons complexes ( capables de renvoyer parfois une valeur parfois une autre) peut faire la différence.
Chez Jest, les bouchons et les espions sont gérés de la même façon :
Et après on a plus qu’a faire des assertions sur le nombre et les modalités d’appels de ce bouchon.

On peut aussi, mocker une fonction asynchrone avec un callback ou qui renverrait une promesse (par exemple un webservice ?)

C’est sympa tout ça mais du coup, pourquoi Jest est mieux ?
Parce que le reste reste simple. (relire cette phrase).
Mettons que je veuille tester une fonction getFooUppercase qui s’appuierai sur une fonction asynchrone getFoo du module ‘module1’ :
Ce qu’on va faire c’est d’importer la dite dépendance et de créer un mock pour la fonction appelée:
Et là c’est génial :
– on peut déclarer un mock n’importe où dans le test il remonte toujours au plus haut niveau ( comme s’il était un « super import »);
– Jest permet, avec async/ await , d’écrire des test sur des fonctions asynchrones presque comme si elles étaient synchrones;
– Jest enregistre tous les appels des fonctions mockés et leurs paramètres ce qui permet de faire des assertions dessus.
De notre coté, on a testé une application ecrite en Vue Js avec vue-test-utils et Jest.
Un dernier point. Pour garder vos tests propres, vous pouvez créer un module de bouchons ‘dependency1’ dans un dossier qui s’appelle « __mock__ » à coté de vos tests, Jest s’appuiera automatiquement dessus ( plus besoin des jest.mock) .
Qu’est ce qu’on pourrais faire de mieux ?
Améliorer la documentation. Notamment celle de l’automocking, une feature dont je n’ai pas parlé ici… …parce que j’ai été incapable de la faire fonctionner.
Je n’ai pas non plus abordé les format de rapport de test et la couverture de code, ça peut aussi guider le choix d’un test runner. De ce coté là, Jest embarque IstanbulJs, qui fait bien le travail.
 Si ça te botte d’en discuter, que tu galère à le faire sur ton projet, ou que juste tu es curieux, n’hésite pas à nous contacter.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

1 × deux =