TL;DR : Activez la compilation Ahead-Of-Time (AOT) pour vos tests Angular afin d'obtenir une couverture précise du code du modèle, une exécution plus rapide des tests, une symétrie de production et une pérennité tests.
L'option est déjà disponible pour les utilisateurs de Vitest et le sera bientôt pour les utilisateurs de Karma et Jest (constructeur expérimental).
Que vous utilisiez Karma, Jest ou Vitest, vous utilisez probablement la compilation Just-In-Time (JIT) pour vos tests Angular, car jusqu'à récemment, c'était la seule option disponible.
Le problème est que JIT présente quelques inconvénients importants :
Depuis Angular 8 et l'introduction d'IVy, le compilateur Angular a commencé à transformer les modèles en instructions. Parmi de nombreux autres avantages, cela signifiait également que les outils de couverture de code pouvaient mapper ces instructions au modèle et calculer la couverture de code en conséquence.
Théoriquement, il est possible de produire une couverture de code en exécutant des tests avec AOT depuis Angular 8, mais l'option n'était pas disponible dans Karma ou Jest. Il n'a été possible d'activer AOT pour les tests que depuis que le support Vitest pour Angular a été ajouté par l'équipe Analog.
En novembre 2024 :
Que vous utilisiez JIT ou AOT, les composants finiront par être compilés à un moment donné. La principale différence est qu'avec AOT, la compilation est effectuée une seule fois et peut être mise en cache, tandis qu'avec JIT, chaque module de test peut finir par recompiler les composants.
Cela signifie que même si la phase de transformation est un peu plus lente avec AOT, le temps global d'exécution du test sera plus rapide. Les chiffres que j'ai vus indiquent une exécution environ 20 % plus rapide, mais cela dépendra fortement de la structure de vos tests et du système testé.
Nous souhaitons généralement que nos tests soient aussi symétriques que possible par rapport à l'environnement de production pour accroître la confiance. Ceci est souvent difficile car il faut tenir compte d'autres propriétés telles que la vitesse des tests, la taille du système testé ou la prévisibilité.
L'aspect intéressant de l'AOT est qu'il améliore la symétrie de la production sans nuire aux autres propriétés. En utilisant AOT, vous gagnerez plus de confiance et obtiendrez un comportement plus proche de la production.
Plus important encore, JIT a atteint ses limites et devient un handicap pour Angular. Par exemple, certaines fonctionnalités angulaires ne sont tout simplement pas prises en charge dans JIT (par exemple, les vues différées). D'autres fonctionnalités potentielles de la feuille de route Angular, comme les composants sans sélecteur, seront probablement impossibles à utiliser avec JIT.
En fait, depuis les entrées de signal d'Angular (et les API fonctionnelles similaires), JIT nécessite déjà quelques transformations minimales pour fonctionner.
En passant à AOT, vous rendez vos tests évolutifs, prêts à bénéficier de toute innovation et préparés à tout ce que l'avenir réserve au JIT.
En activant AOT, certaines techniques qui reposent sur des constructions dynamiques cesseront de fonctionner.
Par exemple, une telle utilisation ne fonctionnera plus :
// ? This is broken with AOT. const fixture = render(`<app-button></app-button>`, { imports: [Button] }); function render(template, { imports }) { @Component({ template, imports, }) class TestContainer {} return TestBed.createComponent(TestContainer); }
Cependant, contourner la compilation AOT est toujours possible (⚠️ pour l'instant ️⚠️):
function render(template, { imports }) { @Component({ jit: true, template, imports, }) class TestContainer {} return TestBed.createComponent(TestContainer); }
Mon conseil est d'éviter de telles constructions autant que possible et de préférer créer des composants spécifiques aux tests lorsque cela est nécessaire, même si cela peut être un peu plus verbeux. À l'avenir, l'équipe Angular pourrait proposer des alternatives à la fois compatibles AOT et moins passe-partout.
Bien que les tests superficiels ne devraient pas être votre stratégie de test principale car ils sont également moins symétriques en matière de production, ils restent une technique utile à avoir dans votre boîte à outils.
Avec AOT, il est actuellement impossible de remplacer les importations d'un composant à l'aide de TestBed#overrideComponent.
La solution de contournement consiste à remplacer les dépendances du composant au niveau du module à l'aide de l'API du framework de test et à remplacer les composants par leurs doubles de test.
Par exemple, avec Vitest :
// app.cmp.spec.ts vi.mock('./street-map.cmp', async () => { return { StreetMap: await import('./street-map-fake.cmp').then( (m) => m.StreetMapFake ), }; }); // street-map-fake.cmp.ts @Component({ selector: 'app-street-map', template: 'Fake Street Map', }) class StreetMapFake implements StreetMap { // ... }
Bien que cette solution de contournement temporaire soit compatible AOT, elle a un coût :
Pour l'instant, je recommanderais d'utiliser JIT pour les tests peu profonds jusqu'à ce que TestBed#overrideComponent prenne en charge AOT ou jusqu'à ce que l'équipe Angular propose une meilleure alternative. Vous pouvez y parvenir en utilisant une configuration distincte pour les tests superficiels qui utilisent JIT pour les tests correspondant à un modèle spécifique comme *.jit.spec.ts.
Localisez le fichier vite.config.js et activez AOT en définissant l'option jit du plugin Angular sur false :
// ? This is broken with AOT. const fixture = render(`<app-button></app-button>`, { imports: [Button] }); function render(template, { imports }) { @Component({ template, imports, }) class TestContainer {} return TestBed.createComponent(TestContainer); }
Nous avons la possibilité d'utiliser soit Istanbul, soit la v8 native pour la couverture du code. Pour une raison quelconque, toujours en cours d'enquête, le remappage de la couverture Vitest échoue lors de l'utilisation de la version 8. La solution est de recourir à Istanbul à la place.
Assurez-vous d'installer la version de Vitest Istanbul qui correspond à La version majeure de Vitest
function render(template, { imports }) { @Component({ jit: true, template, imports, }) class TestContainer {} return TestBed.createComponent(TestContainer); }
Mettez à jour le vite.config.mts pour activer la couverture via Istanbul :
// app.cmp.spec.ts vi.mock('./street-map.cmp', async () => { return { StreetMap: await import('./street-map-fake.cmp').then( (m) => m.StreetMapFake ), }; }); // street-map-fake.cmp.ts @Component({ selector: 'app-street-map', template: 'Fake Street Map', }) class StreetMapFake implements StreetMap { // ... }
Vous pouvez désormais lancer les tests :
export default defineConfig({ ... plugins: [ angular({ jit: false }), ... ], ... });
cliquez ensuite sur l'icône de couverture et admirez la couverture du code du modèle. ?
(vous trouverez également le rapport de couverture dans le dossier de couverture)
Notez que la couverture est calculée sur la base des instructions générées par le compilateur, ce qui signifie que :
Cela fonctionnera même pour les directives structurelles.
Maintenant, devinez quoi !?
La couverture fonctionne également pour les modèles en ligne ! ?
Bien que la couverture de code soit un outil utile, elle doit être utilisée à bon escient. Gardez-le comme un indicateur, pas comme un objectif rigide.
Toute régularité statistique observée aura tendance à s'effondrer une fois qu'une pression sera exercée sur elle à des fins de contrôle.
--Charles Goodhart
En d'autres termes, lorsqu'une mesure devient un objectif, elle cesse d'être une bonne mesure.
J'ajouterais que les mesures les plus simples sont souvent les plus trompeuses.
Les utilisateurs de Karma pourront bientôt activer AOT avec un simple indicateur.
Les utilisateurs de Jest ont trois options :
Les utilisateurs de Vitest peuvent profiter des avantages d'AOT dès maintenant. ?
Si vous en avez assez des bugs ou des tests nécessitant une maintenance élevée qui échouent à chaque refactor, mon cours vidéo, Pragmatic Angular Testing, est là pour vous aider !
Découvrez des stratégies de test pratiques et fiables pour maintenir vos applications Angular stables et maintenables. (Maintenant 50 % de réduction pour une durée limitée !)
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!