web-dev-qa-db-fra.com

Obtention d'une erreur de fournisseur inconnu lors de l'injection d'un service dans un test unitaire Angular

Je suis assez nouveau pour Angular et j'ai passé en revue toutes les questions similaires sur Stack Overflow mais aucune ne m'a aidé. Je crois que tout est correctement configuré mais je reçois toujours un "fournisseur inconnu" erreur lors de la tentative d'injecter un service dans un test unitaire. J'ai présenté mon code ci-dessous - j'espère que quelqu'un peut repérer une erreur évidente!

Je définis mes modules dans un fichier séparé . Js comme ceci:

angular.module('dashboard.services', []);
angular.module('dashboard.controllers', []);

Voici où je définis un service appelé EventingService (avec la logique supprimée par souci de concision):

angular.module('dashboard.services').factory('EventingService', [function () {
    //Service logic here
}]);

Voici mon contrôleur qui utilise EventingService (tout cela fonctionne très bien à l'exécution):

angular.module('dashboard.controllers')
    .controller('Browse', ['$scope', 'EventingService', function ($scope, eventing) {
        //Controller logic here
}]);

Voici mon test unitaire - c'est la ligne où j'essaie d'injecter l'EventingService qui provoque une erreur lorsque j'exécute le test unitaire:

describe('Browse Controller Tests.', function () {
    beforeEach(function () {
        module('dashboard.services');
        module('dashboard.controllers');
    });

    var controller, scope, eventingService;

    beforeEach(inject(function ($controller, $rootScope, EventingService) {
        scope = $rootScope.$new();
        eventingService = EventingService

        controller = $controller('Browse', {
            $scope: scope,
            eventing: eventingService
        });
    }));


    it('Expect True to be True', function () {
        expect(true).toBe(true);
    });
});

Lorsque j'exécute le test, j'obtiens cette erreur:

Erreur: fournisseur inconnu: EventingServiceProvider <- EventingService

Je me suis assuré que mon fichier jasmine specrunner.html contient tous les fichiers source nécessaires (il s'agit d'un projet Asp.Net MVC):

<!-- Include source files here... -->
@Scripts.Render("~/bundles/jquery")
<script type="text/javascript" src="@Url.Content("~/Scripts/angular.js")"></script>  
<script type="text/javascript" src="@Url.Content("~/Scripts/angular-mocks.js")"></script>                 

<script type="text/javascript" src="@Url.Content("~/App/scripts/app.js")"></script>                       <!-- Angular modules defined in here -->
<script type="text/javascript" src="@Url.Content("~/App/scripts/services/eventing.js")"></script>         <!-- My Eventing service defined here -->


<script type="text/javascript" src="@Url.Content("~/App/scripts/controllers/browse.js")"></script>        <!-- My Browse controller defined here -->

<!-- Include spec files here... -->
<script type="text/javascript" src="@Url.Content("~/App/tests/browse.js")"></script>                      <!-- The actual unit test here -->

Je n'arrive pas à comprendre pourquoi Angular lance cette erreur pour se plaindre de mon EventingService. Mon contrôleur fonctionne très bien à l'exécution - c'est juste lorsque j'essaie de le tester que j'obtiens une erreur, donc je suis curieux quant à savoir si j'ai foiré quelque chose avec la moquerie/injection.

L'aide Angular sur les tests est des ordures, donc je suis perplexe à l'heure actuelle - toute aide ou suggestion que n'importe qui pourrait donner serait très appréciée. Merci.

30
Dud

Je suis juste tombé sur cela et l'ai résolu en passant à obtenir le service en utilisant explicitement l'injecteur $:

var EventingService, $rootScope;
beforeEach(inject(function($injector) {
  EventingService = $injector.get('EventingService');
  $rootScope = $injector.get('$rootScope');
}));

J'aimerais pouvoir vous dire pourquoi cela fonctionne et pourquoi le simple

beforeEach(inject(function(EventingService) {   ....  }));

ne le fait pas, mais je n'ai pas le temps d'enquêter sur les internes. Il est toujours préférable d'utiliser un style de codage et de s'y tenir.

Ce style est meilleur dans la mesure où le nom de la variable que vous utilisez dans vos tests est le nom correct du service. Mais c'est un peu bavard.

Il y a une autre angular magique qui utilise des noms de variables étranges comme $ rootScope mais je n'aime pas l'aspect hacky de cela.

Notez que la plupart du temps, les gens obtiennent cette erreur car ils n'ont pas inclus les modules:

beforeEach(module('capsuling'));
beforeEach(module('capsuling.capsules.services'));
26
felix

Si vos contrôleurs (définis sous dashboard.controllers module) dépendent de certains services inclus dans un module différent (dashboard.services) que vous avez besoin de référencer les modules de dépendance dans votre signature de module:

angular.module('dashboard.services', []);
angular.module('dashboard.controllers', ['dashboard.services']);
6
Stewie

Bien que cette question soit assez ancienne, j'ai perdu beaucoup de temps à résoudre un problème similaire à celui-ci, à savoir:

Error: Unknown provider: SomeServiceProvider <- SomeService

Par conséquent, je laisse ici une autre cause possible de ce problème. J'espère que cela serait utile à quelqu'un.

Dans mon cas, j'avais dans mon projet deux modules portant exactement le même nom mais avec des dépendances différentes en cours de création, c'est-à-dire deux fichiers .js différents avec:

angular.module('moduleName', [dependencies]))

De angular:

Passer un argument récupère un angular.Module existant, tandis que passer plus d'un argument crée un nouveau angular.Module

Conclusion: Il s'avère que ce qui était injecté dans le test était le module avec les mauvaises dépendances. La suppression du deuxième argument du module créé par erreur a résolu le problème.

2
Emanuel Miranda

Avez-vous essayé de définir un module supplémentaire qui dépend de vos autres modules agrégés comme ceci:

angular.module( 'dashboard', [ 'dashboard.services', 'dashboard.controllers' ] )

Ainsi, vous pouvez dans le beforeEach spécifier le module qui a les deux sous-modules définis comme ceci:

describe('Browse Controller Tests.', function () {
    beforeEach(function () {
        module('dashboard');
    });

    var controller, scope, eventingService;

    beforeEach(inject(function ($controller, $rootScope, EventingService) {
        scope = $rootScope.$new();
        eventingService = EventingService

        controller = $controller('Browse', {
            $scope: scope,
            eventing: eventingService
        });
    }));


    it('Expect True to be True', function () {
        expect(true).toBe(true);
    });
});
0
user2562481