Composant avec service async
Dans cet exemple, le modèle AboutComponent héberge a TwainComponent.
Les TwainComponent affiches Mark Twain cite.
Notez que la valeur de la propriété quote du composant passe par un AsyncPipe.
Cela signifie que la propriété retourne un Promise ou un Observable.
Dans cet exemple, la méthode TwainComponent.getQuote() vous indique que la propriété quote retourne un Observable.
Le TwainComponent obtient des citations d'un injecté TwainService.
Le composant commence le retour Observable avec une valeur de marque de réservation ( '...') avant que le service puisse renvoyer son premier devis.
Le catchErrorservice intercepte les erreurs, prépare un message d'erreur et renvoie la valeur d'espace réservé sur le canal de réussite errorMessage.
Pour éviter de mettre à jour ce message deux fois au cours du même cycle de détection de changement, vous devez attendre une coche pour le définir.
Ce sont toutes les fonctionnalités que vous voudrez tester.
Test avec un espion
Lors du test d'un composant, seule l'API publique du service doit être importante.
En général, les tests eux-mêmes ne doivent pas appeler des serveurs distants.
Ils devraient imiter de tels appels.
La configuration dans cette app/twain/twain.component.spec.ts montre une façon de faire :
Concentrez-vous sur l'espion.
L'espion est conçu pour que tout appel à recevoir getQuote un observable avec un devis de test.
Contrairement à la méthode getQuote() réelle, cet espion contourne le serveur et renvoie un observable synchrone dont la valeur est disponible immédiatement.
Vous pouvez écrire de nombreux tests utiles avec cet espion, même s'il Observable est synchrone.
tests synchrones
Un avantage clé d'un synchrone Observable est que vous pouvez souvent transformer des processus asynchrones en tests synchrones.
étant donné que le résultat de l'espionnage est renvoyé de manière synchrone, la méthode getQuote() met à jour le message
à l'écran immédiatement après le premier cycle de détection de changement au cours duquel Angular appelle ngOnInit.
Vous n'êtes pas aussi chanceux lorsque vous testez le chemin d'erreur.
Bien que l'espion de service renvoie une erreur de manière synchrone, la méthode du composant appelle setTimeout().
Le test doit attendre au moins un tour complet du moteur JavaScript avant que la valeur ne soit disponible.
Le test doit devenir asynchrone.
Test async avec le fakeAsync()
Pour utiliser les fonctionnalités fakeAsync(), vous devez importer zone-testing.
Le test suivant confirme le comportement attendu lorsque le service renvoie un ErrorObservable.
Notez que la fonction it() reçoit un argument de la forme suivante.
La fonction fakeAsync() permet un style de codage linéaire en exécutant le corps de test dans un programme spécial fakeAsync test zone.
Le corps du test semble être synchrone. Il n'y a pas de syntaxe imbriquée (comme a Promise.then()) pour perturber le flux de contrôle.
Le fonction tick()
Vous devez appeler tick() pour avancer l'horloge (virtuelle).
L'appel tick() simule le passage du temps jusqu'à la fin de toutes les activités asynchrones en attente.
Dans ce cas, il attend le gestionnaire d'erreurs setTimeout();
La fonction tick() accepte les millisecondes en paramètre (la valeur par défaut est 0 si elle n'est pas fournie).
Le paramètre représente l'avancée de l'horloge virtuelle.
Par exemple, si vous avez un setTimeout(fn, 100) dans un test fakeAsync(), vous devez utiliser tick(100) pour déclencher le rappel fn.
Cette fonction tick() est l'un des utilitaires de test Angular que vous importez avec TestBed.
C'est un compagnon fakeAsync() et vous ne pouvez l'appeler que dans un corps fakeAsync().
Comparaison des dates dans le fakeAsync()
fakeAsync() simule le passage du temps, ce qui vous permet de calculer la différence entre les dates à l'intérieur fakeAsync().
jasmine.clock avec le fakeAsync()
Jasmine fournit également une fonctionnalité clock permettant de se moquer des dates.
Angular exécute automatiquement les tests qui sont exécutés après jasmine.clock().install() est appelée dans une méthode fakeAsync() jusqu'à
ce qu'elle jasmine.clock().uninstall() soit appelée. fakeAsync() n'est pas nécessaire et génère une erreur si imbriqué.
Par défaut, cette fonctionnalité est désactivée.
Pour l'activer, définissez un indicateur global avant l'importation zone-testing.
Si vous utilisez la CLI Angular, configurez cet indicateur dans src/test.ts.
Utilisation du planificateur RxJS dans le fakeAsync()
Vous pouvez également utiliser le planificateur RxJS de la fakeAsync() même manière que vous utilisez setTimeout() ou setInterval(),
mais vous devez importer un correctif zone.js/dist/zone-patch-rxjs-fake-async pour le planificateur RxJS.
Soutenir plus macroTasks
Par défaut, fakeAsync() prend en charge les éléments suivants macroTasks.
- setTimeout
- setInterval
- requestAnimationFrame
- webkitRequestAnimationFrame
- mozRequestAnimationFrame
Si vous exécutez d'autres macroTask tels que HTMLCanvasElement.toBlob(), l'erreur "Unknown macroTask scheduled in fake async" sera levée.
canvas.component.spec.ts
canvas.component.ts
Si vous souhaitez prendre en charge ce type de cas, vous devez définir le type macroTask de prise en charge que vous souhaitez prendre en charge beforeEach().
Par exemple :
L'observables async
Vous pourriez être satisfait de la couverture de test de ces tests.
Mais vous pourriez être troublé par le fait que le vrai service ne se comporte pas vraiment de cette façon.
Le service réel envoie des demandes à un serveur distant.
Un serveur met du temps à répondre et la réponse ne sera certainement pas disponible immédiatement comme lors des deux tests précédents.
Vos tests reflètent le monde réel plus fidèlement si vous retournez un asynchrone observable de l'espion getQuote() comme celui-ci.
Async aides observables
L'observable async a été produit par un assistant asyncData.
L'aide asyncData est une fonction utilitaire que vous devrez écrire vous-même.
Ou vous pouvez copier celui-ci à partir de l'exemple de code.
L'observable de cet assistant émet la valeur data lors du prochain tour du moteur JavaScript.
L'opérateur RxJSdefer() renvoie un observable.
Il faut une fonction d'usine qui retourne une promesse ou une observable.
Lorsqu'un élément s'abonne pour différer l'observable, il ajoute l'abonné à un nouvel observable créé avec cette fabrique.
L'opérateur defer() transforme le Promise.resolve() en une nouvelle observable qui, comme HttpClient, émet une fois et complète.
Les abonnés sont désabonnés après avoir reçu la valeur de données.
Il existe une aide similaire pour générer une erreur asynchrone.
Tests asynchrones
Maintenant que l'espion getQuote() retourne des observables asynchrones, la plupart de vos tests devront également être asynchrones.
Voici un test fakeAsync() qui montre le flux de données que vous attendez dans le monde réel.
Notez que l'élément quote affiche la valeur de l'espace réservé ('...') après ngOnInit().
La première citation n'est pas encore arrivée.
Pour vider la première citation de l'observable, vous appelez tick().
Appelez ensuite detectChanges() pour dire à Angular de mettre à jour l'écran.
Ensuite, vous pouvez affirmer que l'élément quote affiche le texte attendu.
Test async avec async()
Pour utiliser les fonctionnalités async(), vous devez importer zone-testing.
La fonction fakeAsync() utilitaire a quelques limitations.
En particulier, cela ne fonctionnera pas si le corps de test passe un appel XHR.
Les appels XHR dans un test sont rares, vous pouvez donc généralement vous en tenir à fakeAsync().
Mais si vous avez besoin d'appeler XHR, vous voudrez savoir async().
La méthode TestBed.compileComponents() appelle XHR à lire les fichiers de modèle et css externes lors de la compilation "juste à temps".
Ecrire des tests qui appellent compileComponents() avec l'async() utilitaire.
Voici le test fakeAsync() précédent , ré-écrit avec l'utilitaire async().
L'utilitaire async() masque un passe-partout asynchrone en faisant en sorte que le code du testeur soit exécuté dans une zone de test asynchrone spéciale.
Vous n'avez pas besoin de passer done() le test de Jasmine au test et à l'appel done() car il s'agit d'une promesse undefined ou de rappels observables.
Mais la nature asynchrone du test est révélée par l'appel à fixture.whenStable(), qui rompt le flux de contrôle linéaire.
Si vous utilisez un intervalTimer() tel que setInterval() dans async(), n'oubliez pas d'annuler le chronomètre clearInterval() après le test,
sinon le programme async() ne se termine jamais.
whenStable
Le test doit attendre que l'observable getQuote() émette le prochain devis.
Au lieu d'appeler tick(), il appelle fixture.whenStable().
Les déclarations fixture.whenStable() d'une promesse qui résout lorsque la file d'attente des tâches du moteur JavaScript est vide.
Dans cet exemple, la file d'attente des tâches devient vide lorsque l'observable émet le premier devis.
Le test reprend dans le rappel de promesse, qui appelle detectChanges() à mettre à jour l'élément quote avec le texte attendu.
Jasmine done()
Bien que les fonctions async() et fakeAsync() simplifient grandement les tests asynchrones d'Angular,
vous pouvez toujours revenir à la technique traditionnelle et transmettre une fonction qui prend un appel doner.
Vous ne pouvez pas appeler done() dans async() ou fakeAsync() fonctions, parce que le done parameter est undefined.
Vous êtes maintenant responsable du chaînage des promesses, du traitement des erreurs et des appels done() aux moments appropriés.
écrire des fonctions de test avec done(), est plus lourd que async() et fakeAsync().
Mais il est parfois nécessaire que le code implique le intervalTimer() même setInterval.
Voici deux autres versions du test précédent, écrites avec done().
Le premier s'abonne à l'exposé Observable au modèle par la propriété quote du composant.
L'opérateur last() RxJS émet la dernière valeur de l'observable avant la fin, qui sera le devis de test.
Le subscribecallback appelle detectChanges() à mettre à jour l'élément quote avec le devis test,
de la même manière que les tests précédents.
Dans certains tests, vous êtes plus intéressé par la façon dont une méthode de service injectée a été appelée et par ses valeurs
renvoyées que par ce qui apparaît à l'écran.
Un espion de service, tel que l'espion qetQuote() du faux TwainService, peut vous donner cette information et faire des affirmations sur l'état de la vue.