33

我对 Angular 还很陌生,并且已经查看了 Stack Overflow 上所有类似的相关问题,但没有一个对我有帮助。我相信我已经正确设置了所有内容,但是在尝试将服务注入单元测试时仍然出现“未知提供者”错误。我在下面列出了我的代码 - 希望有人能发现一个明显的错误!

我在一个单独的.js文件中定义我的模块,如下所示:

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

这是我定义一个名为 EventingService 的服务的地方(为简洁起见,删除了逻辑):

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

这是我使用 EventingService 的控制器(这在运行时都可以正常工作):

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

这是我的单元测试——它是我尝试注入 EventingService 的行,当我运行单元测试时会导致错误:

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);
    });
});

当我运行测试时,我收到此错误:

错误:未知提供者:EventingServiceProvider <- EventingService

我确保我的 jasmine specrunner.html 文件具有所有必要的源文件(这是一个 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 -->

我只是无法理解为什么 Angular 会抛出这个错误来抱怨我的 EventingService。我的控制器在运行时工作正常 - 只是当我尝试测试它时出现错误,所以我很好奇我是否搞砸了模拟/注入。

Angular 对测试的帮助是垃圾,所以我现在很难过 - 任何人都可以提供的任何帮助或建议将不胜感激。谢谢。

4

4 回答 4

27

我刚刚遇到了这个问题,并通过显式切换到使用 $injector 获取服务来解决它:

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

我希望我能告诉你为什么这样有效以及为什么简单

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

没有,但我没有时间调查内部。始终最好使用一种编码风格并坚持下去。

这种风格更好,因为您在测试中使用的变量名称是服务的正确名称。但这有点冗长。

还有另一个角度魔法功能,它使用像$rootScope这样的奇怪变量名,但我不喜欢它的 hacky 外观。

请注意,大多数时候人们收到此错误是因为他们没有包含模块:

beforeEach(module('capsuling'));
beforeEach(module('capsuling.capsules.services'));
于 2013-08-21T10:23:39.563 回答
8

如果您的控制器(在dashboard.controllers模块下定义)依赖于包含在不同模块(dashboard.services)中的某些服务,那么您需要在模块签名中引用依赖模块:

angular.module('dashboard.services', []);
angular.module('dashboard.controllers', ['dashboard.services']);
于 2013-04-04T12:08:58.550 回答
2

虽然这个问题已经相当老了,但我浪费了大量时间来解决与这个类似的问题,即:

Error: Unknown provider: SomeServiceProvider <- SomeService

因此,我将在这里留下另一个可能导致此问题的原因。希望对某人有所帮助。

就我而言,我的项目中有两个名称完全相同但创建了不同依赖项的模块,即两个不同的 .js 文件:

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

从角度文档:

传递一个参数会检索现有的 angular.Module,而传递多个参数会创建一个新的 angular.Module

结论:事实证明,在测试中注入的是具有错误依赖关系的模块。从错误创建的模块中删除第二个参数解决了这个问题。

于 2015-10-27T22:09:13.003 回答
0

您是否尝试过定义一个依赖于其他聚合模块的附加模块,如下所示:

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

因此,您可以在 beforeEach 中指定一个模块,其中定义了两个子模块,如下所示:

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);
    });
});
于 2013-07-08T22:41:42.333 回答