web-dev-qa-db-fra.com

Comment vous moquez-vous d'un service dans AngularJS lorsque vous testez des unités avec du jasmin?

Disons que j'ai un service shop qui dépend de deux services avec état schedule et warehouse. Comment injecter différentes versions de schedule et warehose dans shop pour les tests unitaires?

Voici mon service:

angular.module('myModule').service('shop', function(schedule, warehouse) {
    return {
        canSellSweets : function(numRequiredSweets){
             return schedule.isShopOpen()
                 && (warehouse.numAvailableSweets() > numRequiredSweets);
        }
    }
});

Voici mes moqueries:

var mockSchedule = {
    isShopOpen : function() {return true}
}
var mockWarehouse = {
    numAvailableSweets: function(){return 10};
}

Voici mes tests:

expect(shop.canSellSweets(5)).toBe(true);
expect(shop.canSellSweets(20)).toBe(false);
65
KevSheedy
beforeEach(function () {
  module(function ($provide) {
    $provide.value('schedule', mockSchedule);
  });
});

Le module est une fonction fournie par le module angular-mocks. Si vous transmettez un argument de chaîne, un module portant le nom correspondant est chargé et tous les fournisseurs, contrôleurs, services, etc. sont disponibles pour la spécification. Généralement, ils sont chargés à l'aide de la fonction inject. Si vous transmettez une fonction de rappel, elle sera appelée à l'aide du service $ injector de Angular. Ce service examine ensuite les arguments transmis à la fonction de rappel et essaie de déduire quelles dépendances doivent être transmises au rappel.

52
Attila Miklosi

En améliorant la réponse d'Atilla et en réponse directe au commentaire de KevSheedy, dans le contexte de module('myApplicationModule'), vous procéderiez comme suit:

beforeEach(module('myApplicationModule', function ($provide) {
  $provide.value('schedule', mockSchedule);
}));
36
Matt Richards

Avec CoffeeScript, je rencontre quelques problèmes et j'utilise donc null à la fin:

beforeEach ->
  module ($provide) ->
    $provide.value 'someService',
      mockyStuff:
        value : 'AWESOME'
    null
7

Vous pouvez regarder ici pour plus d'informations

https://docs.angularjs.org/guide/services#unit-testing

Vous voulez utiliser le service $ fournir. Dans ton cas

$provide.value('schedule', mockSchedule);
6
Adam

Comme vous utilisez jasmine, il existe un autre moyen de se moquer des appels avec les espions du jasmin ( https://jasmine.github.io/2.0/introduction.html#section-Spies ).

En les utilisant, vous pouvez être ciblé avec vos appels de fonction et autoriser, si nécessaire, les appels vers l'objet d'origine. Cela évite d’obstruer le haut de votre fichier de test avec les implémentations $ fourniture et fictive.

Dans l'avant de chaque test, j'aurais quelque chose comme:

var mySchedule, myWarehouse;

beforeEach(inject(function(schedule, warehouse) {

  mySchedule = schedule;
  myWarehouse = warehouse;

  spyOn(mySchedule, 'isShopOpen').and.callFake(function() {
    return true;
  });

  spyOn(myWarehouse, 'numAvailableSweets').and.callFake(function() {
    return 10;
  });

}));

et cela devrait fonctionner de la même manière que le mécanisme $ fourniture, en notant que vous devez fournir des instances locales des variables injectées sur lesquelles espionner.

1
bwobbones

J'ai récemment publié le module ngImprovedTesting qui devrait faciliter les tests fictifs sous AngularJS.

Dans votre exemple, il vous suffira de remplacer dans votre test Jasmine le ...

beforeEach(module('myModule'));

... avec ...

beforeEach(ModuleBuilder.forModule('myModule').serviceWithMocks('shop').build());

Pour plus d'informations sur ngImprovedTesting, consultez son article de blog d'introduction: http://blog.jdriven.com/2014/07/ng-improved-testing-mock-testing-for-angularjs-made-easy/ =

1
Emil van Galen

Il est plus simple de mettre la maquette sur le module comme ceci:

    beforeEach(function () {
    module('myApp');
    module({
      schedule: mockSchedule,
      warehouse: mockWarehouse
     }
    });
  });

vous pouvez utiliser l'injection pour obtenir une référence à ces modèles pour les manipulations préalables au test:

var mockSchedule;
var mockWarehouse;

beforeEach(inject(function (_schedule_, _warehouse_) {
     mockSchedule = _schedule_;
     mockWarehouse = _warehouse_;
}));
1
Gal Morad

J'espère que ma réponse n'est pas inutile, mais vous pouvez vous moquer des services en $provide.service

beforeEach(() => {
    angular.mock.module(
      'yourModule',
      ($provide) => {
        $provide.service('yourService', function() {
          return something;
        });
      }
    );
  });
1
Clemens Basler