JavaScript est un langage de type dynamique, qui lui donne une forte capacité de performance, mais rend également le compilateur presque impossible à fournir une aide aux développeurs. Pour cette raison, nous pensons que la rédaction de tout code JavaScript doit avoir un ensemble puissant et complet de tests. Angular a de nombreuses fonctionnalités qui nous permettent de tester plus facilement nos applications. Nous ne devrions avoir aucune excuse pour ne pas rédiger des tests (c'est tout ...).
1. Il s'agit de ne pas mélanger les préoccupations (il s'agit d'éviter que la relation de code se complique ...)
Les tests unitaires, en tant que nom, consiste à tester une seule "unité". Les tests unitaires s'efforcent de répondre à ces questions: suis-je déjà correct dans mes considérations logiques? Les résultats obtenus par la méthode de tri sont-ils corrects? Pour répondre à ces questions, il est particulièrement important de les séparer. En effet, lorsque nous testons la méthode de tri, nous ne voulons pas nous soucier d'autres fragments connexes, tels que les éléments DOM ou initier des demandes XHR pour obtenir des données, etc. De toute évidence, il est généralement difficile d'appeler une fonction séparément dans un projet typique. Ce qui cause ce problème, c'est que les développeurs rendent souvent les relations compliquées et finissent par donner à un extrait comme si elle peut tout faire. Il obtient les données via XHR, trie les données, puis manipule le DOM. Avec Angular, nous pouvons écrire un meilleur code plus facilement, donc Angular nous fournit une injection de dépendance de XHR (que nous pouvons simuler) et Angular crée également des abstractions qui nous permettent de trier le modèle sans avoir à manipuler le DOM. Ainsi, à la fin, nous pouvons simplement écrire une méthode de tri, puis créer un établissement de données via le cas de test pour que la méthode de tri soit utilisée lors du test, puis déterminer si le modèle de résultat répond aux attentes. Le test ne nécessite pas d'attendre que XHR crée le DOM correspondant et détermine si la fonction fonctionne correctement le DOM. L'idée principale d'Angular comprend la testabilité du code, mais nous oblige également à faire la bonne chose. Angular s'engage à simplifier la façon de faire la bonne chose, mais Angular n'est pas magique, ce qui signifie que nous pouvons nous retrouver avec une application non testable si nous ne suivons pas les points suivants.
1. Injection de dépendance
Il existe de nombreuses façons d'obtenir les ressources de dépendance: 1) Nous pouvons utiliser le nouvel opérateur; 2) Nous utilisons une méthode bien connue appelée "Global Singleton"; 3) Nous pouvons le demander au service de registre (mais comment obtenir un registre? Vous pouvez vérifier les chapitres suivants); 4) Nous pouvons nous attendre à ce qu'il soit passé.
Parmi les méthodes énumérées ci-dessus, seul le dernier est testable, voyons pourquoi:
1) Utilisation du nouvel opérateur
Il n'y a essentiellement aucune erreur lors de l'utilisation du nouvel opérateur, mais le problème est que l'appel du constructeur via un nouveau liera définitivement l'appelant au type. Par exemple, nous essayons d'instancier un objet XHR afin que nous puissions obtenir des données du serveur.
function myClass () {this.dowork = function () {var xhr = new xrh (); xhr.open (méthode, url, true); xhr.OnreadyStateChange = function () {…}; xhr.send (); }}Le problème est que lors des tests, nous devons généralement instancier un XHR virtuel qui peut renvoyer des données de test ou des erreurs de réseau. En appelant New Xhr (), nous lions en permanence le vrai XHR et il n'y a aucun bon moyen de le remplacer. Bien sûr, il y a un mauvais remède et il y a de nombreuses raisons de prouver que c'est une mauvaise idée:
var oldxhr = xhr; xhr = new MockXhr () {}; myClass.Dowork (); // jugez si Mockxhr appelle xhr = oldxhr à travers des paramètres normaux; // Si vous oubliez cette étape, il est facile de provoquer des choses tristes.2) Recherche globale
Une autre façon de résoudre le problème est d'obtenir les ressources de dépendance dans un endroit bien connu.
function myClass () {this.dowork = function () {global.xhr ({…}); };}Sans créer une instance d'un nouvel objet dépendant, le problème est fondamentalement le même que nouveau, et il n'y a pas de bon moyen d'intercepter les appels globaux.xhr lors du test. Le problème le plus élémentaire avec les tests est que les variables globales doivent être modifiées pour appeler des méthodes virtuelles et sont modifiées. Pour en savoir plus sur ses inconvénients, visitez ici: http://misko.hevery.com/code-reviewers-guide/flaw-bittle-global-state-singletons/
Le code ci-dessus est difficile à tester, nous devons donc modifier l'état global:
var oldxhr = global.xhr; global.xhr = fonction mockxhr () {…}; var myClass = new myClass (); // juge si Mockxhr appelle global.xhr = oldxhr à travers des paramètres normaux; // Si vous oubliez cette étape, il est facile de provoquer des choses tristes.3) Registre des services
Avoir un registre avec tous les services semble résoudre le problème, puis remplacer le service requis dans le code de test.
function myClass () {var ServiceRegistry = ???; this.dowork = function () {var xhr = ServiceRegistry.get ("xhr"); …};}Mais d'où vient le service. Si c'est le cas: * New-Ed Up, le test n'a aucune chance de réinitialiser les services pour les tests * Recherche globale, alors le service renvoyé est également global (mais la réinitialisation est plus facile, car il n'y a qu'une seule variable globale à réinitialiser) (le texte derrière ici est le même que le brouillage ... Je n'ai pas compris)
Selon cette méthode, modifiez la classe ci-dessus à la méthode suivante:
var oldServiceLocator = global.servicelocator; global.servicelocator.set ('xhr', fonction mockxhr () {}); var myClass = new myclass (); myclass.dowork (); // juge si mockxhr appelle global.serviceloator = oldServiceLocator; // Si vous oubliez cette étape, il est facile de provoquer des choses tristes.4) transmettre des dépendances
Enfin, les ressources de dépendance peuvent être transmises.
function myClass (xhr) {this.dowork = function () {xhr ({…}); };}Il s'agit de la méthode préférée, car le code n'a pas besoin de prêter attention à l'origine du XHR, et il ne se soucie pas de qui a créé le XHR transmis. Par conséquent, le créateur de la classe peut être codé séparément de la classe de la classe, ce qui sépare la responsabilité de la création de la logique, qui est un aperçu de l'injection de dépendance.
Cette classe est facile à tester, et nous pouvons l'écrire comme celle-ci dans le test:
fonction xhrmock (args) {…} var myClass = new myClass (xhrmock); myclass.dowrok (); // porte des jugements ... via ce code de test, nous pouvons réaliser qu'aucune variable globale n'est corrompue.Dependency-Injection (//www.vevb.com/article/91775.htm) inclus avec le code angulaire, écrit de cette manière, il est plus facile d'écrire le code de test. Si nous voulons écrire du code très testable, nous ferions mieux de l'utiliser.
2. Contrôleurs
La logique rend chaque application unique, et c'est ce que nous voulons tester. Si notre logique est mélangée avec les opérations DOM, ce sera aussi difficile à tester que l'exemple suivant:
Fonction PasswordController () {// Obtenez une référence à l'objet DOM var msg = $ ('. Ex1 Span'); Var Input = $ ('. EX1 Input'); Var Force; this.grade = function () {msg.reMoveClass (force); var pwd = input.val (); mot de passe.Text (PWD); if (pwd.length> 8) {force = 'Strong'; } else if (pwd.length> 3) {force = 'medium'; } else {force = 'faible'; } msg.addclass (résistance) .Text (force); }}Le code ci-dessus rencontrera des problèmes lors du test car il nous oblige à avoir le DOM correct lors de l'exécution du test. Le code de test sera le suivant:
var input = $ ('<input type = "text" />'); var span = $ ('<span>'); $ ('body'). html ('<div>'). find ('div'). A SPEND (input) .append (span); var pc = new PasswordController (); input.val ('ABC'); pc.grade (); attendre (span.Text ()). Toequal ('faible'); $ ('body'). Html ('');Dans Angular, le contrôleur sépare strictement la logique de l'opération DOM, ce qui réduira considérablement la difficulté d'écrire des cas de test. Jetez un œil à l'exemple suivant:
Fonction PasswordCntrl ($ scope) {$ scope.password = ''; $ scope.grade = function () {var size = $ scope.password.length; if (size> 8) {$ scope.strength = 'Strong'; } else if (size> 3) {$ scope.strength = 'medium'; } else {$ scope.strength = 'faible'; }};}Le code de test est simple:
var pc = new PasswordController ($ scope); pc.password ('abc'); pc.grade (); attendre ($ scope.streng) .toequal ('faible');Il convient de noter que le code de test est non seulement plus discontinu, mais est plus facile à suivre. Nous avons toujours dit que les cas de test racontaient des histoires, et non pour juger d'autres choses non pertinentes.
3. Filtres
Le filtre (http://docs.angularjs.org/api/ng.$Filter) est utilisé pour convertir les données en format convivial. Ils sont importants car ils séparent la responsabilité de convertir les formats à partir de la logique d'application, simplifiant davantage la logique d'application.
mymodule.filter ('longueur', function () {return function (text) {return ('' + (text || '')). length;}}); var longueur = $ filter ('longueur'); attendre (longueur (null)). toequal (0); attendre (longueur ('abc')). toequal (3);4. Directives
5. Mocks
6. Isolement de l'État mondial
7. Moyens de test préférés
8. JavaScriptTestDriver
9. Jasmine
10. Exemple de projet
Nous continuerons à mettre à jour des articles connexes à l'avenir. Merci pour votre soutien à ce site!