为什么针对angular-google-maps提供程序的此测试失败?

时间:2016-08-11 16:16:17

标签: javascript angularjs karma-runner angular-mock angular-providers

我正在尝试测试使用angular-google-maps的模块。它失败了,因为angular.mock.inject找不到uiGmapGoogleMapApiProvider

Error: [$injector:unpr] Unknown provider: uiGmapGoogleMapApiProviderProvider <- uiGmapGoogleMapApiProvider

我无法弄清楚出了什么问题。这是简化的测试用例:

'use strict';

describe('this spec', function() {
    beforeEach(module('uiGmapgoogle-maps'));

    it('tries to configure uiGmapGoogleMapApiProvider', inject(function(uiGmapGoogleMapApiProvider) {
        expect(uiGmapGoogleMapApiProvider.configure).toBeDefined();
    }));
});

整个内容可以作为GitHub中准备好运行的Angular项目提供。如果您发现问题,请在此处回答Stack Overflow。如果您还向GitHub存储库提交拉取请求,则会获得奖励。

2 个答案:

答案 0 :(得分:2)

这里有两个陷阱,这两个陷阱都没有与angular-google-maps有任何关系。

第一个陷阱在于服务和提供者之间的区别。服务,工厂,值和常量的文档states是提供者的特例。对于像我这样的相对初学者,这似乎表明提供者和服务可以以相同的方式在任何地方依赖注入。然而,情况正好相反:在可以注入依赖关系的任何地方,您可以注入提供者或服务,但不能同时注入。

这种分歧的原因在于配置时间和运行时间之间的严格分离(参见module documentation)。提供程序在配置期间可用,而服务在运行时可用。配置时间结束后运行时间开始。 .config.provider块在配置时执行,而大多数其他类型的块在运行时执行。提供者和服务定义之间的关系在以下代码片段中说明,改编自provider documentation

myModule.provider('myServiceProvider', ['injectedProvider', function MyServiceProvider(injectedProvider) {
    // configuration time code depending on injectedProvider

    this.$get = ["injectedService", function MyService(injectedService) {
        // run time code depending on injectedService
    }];

    // more configuration time code
}]);

如您所见,服务在提供商中定义。提供程序在配置时定义(外部块,function MyServiceProvider),并且可能依赖于其他提供程序。可以在运行时使用提供程序的.$get方法从提供程序中提取服务,如内部块(function MyService)所定义,并且可以依赖于其他服务。提供者不能是服务的注入依赖项,反之亦然,但您可以将服务定义嵌套在上面的提供者定义中,以使其依赖于提供者间接。当您使用angular.module(...).service块定义“独立”服务时,Angular会执行类似上面代码的操作。

另一个缺陷是angular.mock.inject,即我问题中单元测试的inject,只能进行运行时注射。对于配置时间注入,您必须通过创建具有配置时间依赖性的新模块来执行“真实的事情”,即非模拟注入。这是mguimard暗示的内容。 AndréEife发表了关于如何做到这一点的简短tutorial,我通过answer底部的链接找到了我的另一个问题。

总之,以下是解决问题的代码:

'use strict';

describe('this spec', function() {
    var gmapProvider;

    beforeEach(function() {
        angular.module('testAssist', ['uiGmapgoogle-maps'])
        .config(function(uiGmapGoogleMapApiProvider) {
            gmapProvider = uiGmapGoogleMapApiProvider;
        });
        module('testAssist');  // angular.mock.module
        inject();              // angular.mock.inject
    });

    it('tries to configure uiGmapGoogleMapApiProvider', function() {
        expect(gmapProvider.configure).toBeDefined();
    });
});

夹具中的'testAssist'模块(beforeEach)的存在的唯一目的是对uiGmapGoogleMapApiProvider具有配置时间依赖性,因此我可以在本地{{1}中捕获后者变量。随后对gmapProvidermodule的调用是簿记技巧,以确保inject config块被执行。由于捕获,在测试用例('testAssist')中不需要进行注入,我只能验证提供者是否有it方法。请注意,第一个configure调用是常规模块定义,而第二个angular.module调用是模拟框架(module)中的特殊构造。

我已将上述解决方案推送到GitHub上的fix1 branch

答案 1 :(得分:-1)

您无法使用inject获取提供者实例,而是使用module