Les équipes travaillant sur des projets d’une taille conséquente connaissent bien ce problème : la lenteur de l'exécution de tous nos tests et donc de nos builds.
Lors de ma dernière mission, lancer l’ensemble des tests Angular (+ de 3500) prenait environ une douzaine de minutes. Autant dire une éternité en informatique !
Et cela devenait problématique dans des cas d’urgence, de déploiements prioritaires, livraisons, etc…
Comment pouvait-on améliorer ceci rapidement et sans trop d’impact sur le projet ?
Découverte de la librairie Ng-Bullet
Nos tests utilisant le framework Jasmine et fortement TestBed d’Angular, nous nous sommes intéressés à Ng-Bullet.
C’est une bibliothèque qui vient surcharger la configuration Angular de chaque TestBed, pour éviter que le framework ne recompile le module cible à chaque test, ce qui a un coût important en terme de temps.
Pour plus de détails sur la mécanique et l’historique de cette librairie, je vous conseille l’article de son créateur.
Ce qui est intéressant à savoir, c’est que les changements à apporter sont minimes et répétitifs, mais nécessitent tout de même la modification de chaque fichier de test. Soit, dans notre cas, plus de 400 fichiers *.spec.ts, de cette manière :
Pour cette tâche de refactoring, il est bien sûr conseillé de répartir la masse de modifications au sein des équipes/membres.
Cela permet à tout le monde de découvrir et mettre en place cette nouvelle syntaxe commune à quasiment tous les tests de composants.
Utilisation : gagnons du temps !
Ces modifications étant similaires à chaque fichier de tests, nous allons pouvoir faire un find/replace sur tous les fichiers de tests *.spec.ts, ce qui nous fera gagner un temps précieux :
(car comme le disait Larry Wall, la paresse est une des vertus d’un programmeur.) |
Pour cela, je vous ai créé 2 regex utilisables dans votre IDE préféré (pour moi IntelliJ) :
1. Pour ajouter l’import ng-bullet et pour remplacer le beforeEach de configuration de module :
Recherche :
(^\A(.*)$)((\n.*)*)(beforeEach\(.*)((\n.*)*TestBed\.configureTestingModule)
Remplace :
import { configureTestSuite } from 'ng-bullet';\n$1$3configureTestSuite(() => {$6
2. Pour retirer le .compileComponents()
et une éventuelle parenthèse en trop :
Recherche :
(\n.*\.compileComponents\(\))(.*\n.*)}\)\)
Remplace :
$2})
Note : Il se peut que quelques uns de vos tests échouent (createComponent
mal placé, Stub/Mock à réinitialiser, …). Il faudra donc, selon votre choix, soit passer manuellement sur chacun d’entre eux, soit laisser le test comme il était avant l’ajout de Ng-Bullet.
Conclusion
- Cette librairie nous a-t-elle aidée dans notre recherche de rapidité d’exécution des TU ?
Oui.
Ayant testé Ng-Bullet sur 2 projets Angular, en modifiant simplement chaque Test Suite, sans recherche particulière d’optimisation, j’ai obtenu ces résultats :
Ce sont effectivement des résultats satisfaisants, le temps passé à effectuer ce refactoring sera largement récupéré par les gains sur les temps de builds/exécutions !
- Peut-on encore améliorer ces temps ?
Bien sûr !
Plusieurs pistes s’offrent à nous :
- Parallélisation des tests
- Retirer les modules non-nécessaires dans chaque
TestBed.configureTestingModule
- Configurer différemment le compilateur
- Abandonner Karma pour Jest (avec ici un article de mon collègue Corentin Bigot)