Maison > interface Web > js tutoriel > Dépendiss moqueurs dans les tests angularjs

Dépendiss moqueurs dans les tests angularjs

Jennifer Aniston
Libérer: 2025-02-20 12:28:16
original
360 Les gens l'ont consulté

Mocking Dependencies in AngularJS Tests

Points de base

  • AngularJS 天生就考虑到了测试,其内置的依赖注入机制使得每个组件都可使用任何 JavaScript 测试框架(如 Jasmine)进行测试。
  • 单元测试中的模拟涉及隔离测试代码片段的功能,这可能具有挑战性,因为依赖项来自不同的来源。 La simulation dans AngularJS est simplifiée avec le module angular-mocks, qui fournit des simulations pour un ensemble de services angularjs couramment utilisés.
  • AngularJS 中的服务模拟可以通过获取实际服务的实例并侦听服务的方法,或者使用 $provide 实现模拟服务来完成。 Cette dernière méthode est préférable, ce qui peut éviter d'appeler la mise en œuvre de la méthode réelle du service.
  • La simulation du fournisseur dans AngularJS suit des règles similaires à la simulation de service. La méthode $get doit être implémentée dans le test. Si la fonction définie dans la fonction $get n'est pas requise dans le fichier de test, il peut se voir attribuer une valeur à une fonction vide.
  • Global objects (such as part of a global "window" object or objects created by third-party libraries) can be simulated by injecting them into $window or using a global object to create values ​​or constants and injecting them au besoin.

Le concept de conception AngularJS comprend des tests. Le code source du cadre est très bien testé et tout code écrit à l'aide du cadre est également testable. Le mécanisme d'injection de dépendance intégré permet de tester chaque composant écrit dans AngularJS. Le code dans les applications AngularJS peut être testé unitaire à l'aide de tout cadre de test JavaScript existant. Le cadre le plus courant utilisé pour tester le code AngularJS est le jasmin. Tous les exemples d'extraits de code de cet article sont écrits à l'aide de Jasmine. Si vous utilisez un autre cadre de test dans votre projet angulaire, vous pouvez toujours appliquer les idées discutées dans cet article.

Cet article suppose que vous avez déjà de l'expérience dans les tests unitaires et tester le code AngularJS. Vous n'avez pas besoin d'être un expert des tests. Si vous avez une compréhension de base des tests et que vous pouvez écrire des cas de test simples pour les applications AngularJS, vous pouvez continuer à lire cet article.

Le rôle de la simulation dans les tests unitaires

La tâche de chaque test unitaire est de tester la fonctionnalité d'un morceau de code isolément. L'isolement du système testé peut parfois être difficile car les dépendances peuvent provenir de différentes sources et nous devons comprendre pleinement les responsabilités de l'objet à simuler.

Dans les langages non typés tels que JavaScript, la simulation est difficile car il n'est pas facile de comprendre la structure de l'objet à simuler. Dans le même temps, il offre également une flexibilité, c'est-à-dire pour ne simuler qu'une partie de l'objet actuellement utilisé par le système testé et ignorer le reste.

MOCK EN ANGULLARJS TEST

Étant donné que l'un des principaux objectifs d'AngularJS est la testabilité, l'équipe principale met des efforts supplémentaires pour faciliter les tests et nous fournit un ensemble de simulations dans le module angular-mocks. Ce module contient des simulations autour d'un ensemble de services angularjs (tels que $http, $timeout, $animate, etc.) qui sont largement utilisés dans toute application angularjs. Ce module réduit le temps qu'il faut aux développeurs pour rédiger des tests.

Ces simulations sont très utiles lors de la rédaction de tests pour de véritables applications commerciales. En même temps, ils ne sont pas suffisants pour tester l'ensemble de l'application. Nous devons se moquer de toutes les dépendances dans le cadre mais non moqué - les dépendances à partir de plugins tiers, d'objets globaux ou de dépendances créées dans l'application. Cet article présentera quelques conseils sur les dépendances AngularJS moqueuses.

Service de simulation

Les services

sont le type de dépendance le plus courant dans les applications AngularJS. Comme vous le savez probablement déjà, les services sont un terme surchargé dans AngularJS. Il peut se référer à un service, une usine, une valeur, une constante ou un fournisseur. Nous discuterons du fournisseur dans la section suivante. Le service peut être simulé de l'une des manières suivantes:

  • Méthodes pour utiliser des blocs d'injection pour obtenir des instances de service réelles et écouter le service.
  • Utiliser $provide pour implémenter les services de simulation.

Je n'aime pas la première méthode car elle peut conduire à l'implémentation réelle de la méthode du service d'appel. Nous utiliserons la deuxième méthode pour simuler le service suivant:

angular.module('sampleServices', [])
  .service('util', function() {
    this.isNumber = function(num) {
      return !isNaN(num);
    };

    this.isDate = function(date) {
      return (date instanceof Date);
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code d'extrait de code suivant crée une simulation du service ci-dessus:

module(function($provide) {
  $provide.service('util', function() {
    this.isNumber = jasmine.createSpy('isNumber').andCallFake(function(num) {
      // 模拟实现
    });
    this.isDate = jasmine.createSpy('isDate').andCallFake(function(num) {
      // 模拟实现
    });
  });
});

// 获取模拟服务的引用
var mockUtilSvc;

inject(function(util) {
  mockUtilSvc = util;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Bien que l'exemple ci-dessus utilise le jasmin pour créer des espions, vous pouvez le remplacer par sinon.js pour atteindre la fonctionnalité équivalente.

Il est préférable de créer toutes les simulations après le chargement de tous les modules requis pour le test. Sinon, si un service est défini dans un module chargé, l'implémentation réelle remplace l'implémentation simulée.

Les constantes, les usines et les valeurs peuvent être simulées séparément en utilisant $provide.constant, $provide.factory et $provide.value.

Fournisseur de simulation

Le fournisseur de simulation est similaire au service de simulation. Toutes les règles qui doivent être suivies lorsque les fournisseurs d'écriture doivent également être suivis lorsqu'ils se moquent d'eux. Considérez le fournisseur suivant:

angular.module('mockingProviders',[])
  .provider('sample', function() {
    var registeredVals = [];

    this.register = function(val) {
      registeredVals.push(val);      
    };

    this.$get = function() {
      function getRegisteredVals() {
        return registeredVals;
      }

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code d'extrait de code suivant crée une simulation pour le fournisseur ci-dessus:

module(function($provide) {
  $provide.provider('sample', function() {
    this.register = jasmine.createSpy('register');

    this.$get = function() {
      var getRegisteredVals = jasmine.createSpy('getRegisteredVals');

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
});

// 获取提供程序的引用
var sampleProviderObj;

module(function(sampleProvider) {
  sampleProviderObj = sampleProvider;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

La différence entre obtenir des références au fournisseur et à d'autres singletons est que le fournisseur n'est pas disponible dans le bloc inject() pour le moment, car le fournisseur est converti en usine pour le moment. Nous pouvons utiliser le bloc module() pour obtenir leurs objets.

Dans le cas de la définition d'un fournisseur, la méthode $get doit également être implémentée dans le test. Si vous n'avez pas besoin de la fonction définie dans la fonction $get dans le fichier de test, vous pouvez l'affecter à une fonction vide.

Module analogique

Si le module à charger dans le fichier de test nécessite un tas d'autres modules, le module testé ne peut être chargé que si tous les modules requis sont chargés. Le chargement de tous ces modules provoque parfois l'échec des tests car certaines méthodes de service réelles peuvent être appelées à partir du test. Pour éviter ces difficultés, nous pouvons créer des modules virtuels pour charger les modules mesurés.

Par exemple, supposons que le code suivant représente un module avec l'exemple de service ajouté:

angular.module('sampleServices', [])
  .service('util', function() {
    this.isNumber = function(num) {
      return !isNaN(num);
    };

    this.isDate = function(date) {
      return (date instanceof Date);
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion

Le code suivant est le bloc beforeEach dans le fichier de test de l'exemple de service:

module(function($provide) {
  $provide.service('util', function() {
    this.isNumber = jasmine.createSpy('isNumber').andCallFake(function(num) {
      // 模拟实现
    });
    this.isDate = jasmine.createSpy('isDate').andCallFake(function(num) {
      // 模拟实现
    });
  });
});

// 获取模拟服务的引用
var mockUtilSvc;

inject(function(util) {
  mockUtilSvc = util;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Alternativement, nous pouvons ajouter l'implémentation simulée du service au module virtuel défini ci-dessus.

Simuler la méthode pour revenir à la promesse

La rédaction d'une application angulaire de bout en bout peut être difficile sans utiliser la promesse. Tester des extraits de code qui s'appuient sur des méthodes qui renvoient la promesse devient un défi. Un espion du jasmin normal fait échouer certains cas de test car la fonction testée attend un objet avec la structure de promesse réelle.

Les méthodes asynchrones peuvent être simulées en utilisant une autre méthode asynchrone qui renvoie une promesse avec une valeur statique. Considérez les usines suivantes:

angular.module('mockingProviders',[])
  .provider('sample', function() {
    var registeredVals = [];

    this.register = function(val) {
      registeredVals.push(val);      
    };

    this.$get = function() {
      function getRegisteredVals() {
        return registeredVals;
      }

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion

Nous testerons la fonction getData() dans l'usine ci-dessus. Comme nous pouvons le voir, il repose sur la méthode de service dataSourceSvc getAllItems(). Nous devons simuler les services et les méthodes avant de tester la fonctionnalité de la méthode getData().

Le service

$q a des méthodes when() et reject() qui permettent à l'utilisation de valeurs statiques de résoudre ou de rejeter la promesse. Ces méthodes sont très utiles pour tester des méthodes de moquerie qui renvoient la promesse. L'extrait de code suivant simule dataSourceSvc usine:

module(function($provide) {
  $provide.provider('sample', function() {
    this.register = jasmine.createSpy('register');

    this.$get = function() {
      var getRegisteredVals = jasmine.createSpy('getRegisteredVals');

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
});

// 获取提供程序的引用
var sampleProviderObj;

module(function(sampleProvider) {
  sampleProviderObj = sampleProvider;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

$q Promise termine son fonctionnement après le prochain cycle de digestion. Le cycle de digest s'exécute en continu dans l'application réelle, mais pas dans le test. Par conséquent, nous devons appeler $rootScope.$digest() manuellement pour faire respecter la promesse. L'extrait de code suivant montre un exemple de test:

angular.module('first', ['second', 'third'])
  // util 和 storage 分别在 second 和 third 中定义
  .service('sampleSvc', function(utilSvc, storageSvc) {
    // 服务实现
  });
Copier après la connexion

Simuler les objets globaux

Les objets globaux proviennent des sources suivantes:

  1. objets qui font partie de l'objet "Window" global (par exemple, localStorage, indexdDB, mathématiques, etc.).
  2. objets créés par des bibliothèques tierces telles que jQuery, soulignement, moment, brise ou toute autre bibliothèque.

Par défaut, les objets globaux ne peuvent pas être simulés. Nous devons suivre certaines étapes pour les rendre simulatiables.

Nous ne voulons peut-être pas simuler des objets mathématiques ou des objets utilitaires (créés par la bibliothèque de sous-oreaux) car leurs opérations n'effectue aucune logique métier, exploitent l'interface utilisateur et ne communiquent pas avec la source de données. Cependant, des objets tels que $ .ajax, localstorage, Websockets, Breeze et Toastr doivent être simulés. Parce que si ces objets ne sont pas moqués, ils effectueront leurs opérations réelles lors de la réalisation de tests unitaires, ce qui peut conduire à certaines mises à jour d'interface utilisateur, des appels réseau et parfois des erreurs dans le code de test. _

En raison d'une injection de dépendance, chaque partie du code écrite en angulaire est testable. DI nous permet de passer tout objet qui suit le cale d'objet réel, juste pour que le code testé ne se casse pas lors de l'exécution. Si les objets globaux peuvent être injectés, ils peuvent être simulés. Il existe deux façons de rendre les objets globaux injectables:

  1. Injecter $window dans le service / contrôleur qui nécessite l'objet global et accéder à l'objet global via $window. Par exemple, les services suivants utilisent LocalStorage via $window:
angular.module('sampleServices', [])
  .service('util', function() {
    this.isNumber = function(num) {
      return !isNaN(num);
    };

    this.isDate = function(date) {
      return (date instanceof Date);
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion
  1. Créez une valeur ou une constante à l'aide d'un objet global et injectez-le là où il est nécessaire. Par exemple, le code suivant est une constante pour Toastr:
module(function($provide) {
  $provide.service('util', function() {
    this.isNumber = jasmine.createSpy('isNumber').andCallFake(function(num) {
      // 模拟实现
    });
    this.isDate = jasmine.createSpy('isDate').andCallFake(function(num) {
      // 模拟实现
    });
  });
});

// 获取模拟服务的引用
var mockUtilSvc;

inject(function(util) {
  mockUtilSvc = util;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Je préfère envelopper des objets globaux avec des constantes plutôt que des valeurs, car les constantes peuvent être injectées dans des blocs de configuration ou des fournisseurs, et les constantes ne peuvent pas être décorées.

l'extrait de code suivant montre la simulation de LocalStorage et Toastr:

angular.module('mockingProviders',[])
  .provider('sample', function() {
    var registeredVals = [];

    this.register = function(val) {
      registeredVals.push(val);      
    };

    this.$get = function() {
      function getRegisteredVals() {
        return registeredVals;
      }

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
Copier après la connexion
Copier après la connexion
Copier après la connexion

Conclusion

La simulation est l'une des composantes importantes de l'écriture de tests unitaires dans n'importe quelle langue. Comme nous l'avons vu, l'injection de dépendance joue un rôle important dans les tests et la simulation. Le code doit être organisé de manière à ce que sa fonctionnalité puisse être facilement testée. Cet article répertorie l'ensemble d'objets le plus courant pour simuler lors du test des applications AngularJS. Le code lié à cet article peut être téléchargé à partir de GitHub.

FAQ sur les dépendances moqueuses dans les tests angularjs (FAQ)

Quel est le but de se moquer des dépendances dans les tests AngularJS?

Les dépendances moqueuses dans les tests angularjs sont un élément clé des tests unitaires. Il permet aux développeurs d'isoler le code testé et de simuler le comportement de leurs dépendances. De cette façon, vous pouvez tester comment votre code interagit avec ses dépendances sans les appeler. Ceci est particulièrement utile lorsque les dépendances sont complexes, lentes ou ont des effets secondaires que vous souhaitez éviter pendant les tests. En se moquant de ces dépendances, vous pouvez vous concentrer sur le test de la fonctionnalité de votre code dans un environnement contrôlé.

Comment créer un service simulé dans AngularJS?

La création d'un service simulé dans AngularJS implique l'utilisation du service $provide dans la configuration du module. Vous pouvez utiliser les méthodes $provide du service value, factory ou service pour définir une implémentation simulée d'un service. Voici un exemple de base:

module(function($provide) {
  $provide.provider('sample', function() {
    this.register = jasmine.createSpy('register');

    this.$get = function() {
      var getRegisteredVals = jasmine.createSpy('getRegisteredVals');

      return {
        getRegisteredVals: getRegisteredVals
      };
    };
  });
});

// 获取提供程序的引用
var sampleProviderObj;

module(function(sampleProvider) {
  sampleProviderObj = sampleProvider;
});
Copier après la connexion
Copier après la connexion
Copier après la connexion

Dans cet exemple, nous utilisons la méthode $provide.value pour définir l'implémentation simulée de myService. Pendant les tests, ce service simulé sera utilisé à la place du service réel.

(Veuillez poser le reste des questions FAQ une par une en raison des limitations de l'espace, et je ferai de mon mieux pour fournir des réponses concises et claires.)

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!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal