13

我需要我的应用在运行时通过 HTTP 端点运行一些配置。

我写了一个简单的服务来做到这一点:

module.factory('config', function ($http, analytics) {
    return {
        load: function () {
            $http.get('/config').then(function (response) {
                analytics.setAccount(response.googleAnalyticsAccount);
            });
        }
    }
});

接下来,我在我的应用程序模块的运行块中调用此模块:

angular.module('app').***.run(function(config) {
        config.load();
    });

应用程序运行时一切正常,但在我的单元测试中,我收到此错误:“错误:意外请求:GET /config”

我知道这意味着什么,但我不知道当它从运行块发生时如何模拟它。

谢谢你的帮助

编辑以添加规格

在每个之前调用它

beforeEach(angular.mock.module('app'));

试过这个来模拟 $httpBackend:

beforeEach(inject(function($httpBackend) {

    $httpBackend.expectGET('/config').respond(200, {'googleAnalyticsAccount':});

    angular.mock.module('app')

    $httpBackend.flush();
}));

但得到:

TypeError: Cannot read property 'stack' of null
        at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55)
    TypeError: Cannot read property 'stack' of null
        at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55)
    TypeError: Cannot read property 'stack' of null
        at workFn (/Users/arnaud/workspace/unishared-dredit/test/lib/angular/angular-mocks.js:1756:55)

编辑自更新到 AngularJS 1.0.6

由于我已经更新到 AngularJS 1.0.6,由 Angular 团队的 Igor 建议,问题已经消失,但现在我有了这个,这听起来更“正常”,但我仍然不知道如何制作有用。

Error: Injector already created, can not register a module!
4

3 回答 3

16

我为这个错误挣扎了一会儿,但设法想出了一个明智的解决方案。

我想要实现的是成功存根服务并强制响应,在控制器上,可以$httpBackend在启动控制器之前使用请求存根或异常。在app.run()您加载时,module它会初始化对象及其连接的服务等。

我设法使用以下示例对服务进行存根。

describe('Testing App Run', function () {
    beforeEach(module('plunker', function ($provide) {
        return $provide.decorator('config', function () {
            return {
                load: function () {
                    return {};
                }
            };
        });
    }));


    var $rootScope;
    beforeEach(inject(function (_$rootScope_) {
        return $rootScope = _$rootScope_;
    }));

    it("defines a value I previously could not test", function () {
        return expect($rootScope.value).toEqual('testing');
    });

});

我希望这对您app.run()将来的测试有所帮助。

于 2013-04-17T16:52:56.610 回答
5

我不知道你是否还在寻找这个问题的答案。但这里有一些信息可能会有所帮助。

$injector 是一个应用程序的单例,而不是一个模块。但是, angular.injector 实际上会尝试为每个模块创建一个新的注入器(我想你有一个

beforeEach(module("app")); 

一开始。

我在使用 Angular、RequireJS、Karma 和 Jasmine 时遇到了同样的问题,我想出了两种解决方法。我在我的测试中为注入器功能创建了一个提供程序作为单独的依赖项。例如 MyInjectorProvider,它提供了一个 $injector 的单例实例。

另一种方法是移动以下语句:

beforeEach(module("app"));
beforeEach(inject(function($injector){
    ...
})

在测试套件描述中。所以这是它以前的样子:

define(['services/SignupFormValidator'], function(validator){
    var validator;
    beforeEach(module("app"));
    beforeEach(inject(function($injector){
        validator = $injector.get("SignupFormValidator");
    })

    describe("Signup Validation Tests", function(){
        it("...", function(){...});
    });
});

应用修复后,它看起来像这样:

define(['services/SignupFormValidator'], function(validator){
    var validator;

    describe("Signup Validation Tests", function(){
        beforeEach(module("app"));
        beforeEach(inject(function($injector){
            validator = $injector.get("SignupFormValidator");
        });

        it("...", function(){...});
    });
});

这两种解决方案都适用于我的情况。

于 2013-11-05T01:58:22.883 回答
1

您应该使用ngMock.$httpBackend模拟每个 HTTP 请求。另外,这里有一个指南


更新

你不需要这个angular.mock.module东西,只需要注入你的应用程序模块。像这样的东西:

var httpBackend;

beforeEach(module('app'));
beforeEach(inject(function($httpBackend) {
  httpBackend = $httpBackend;
  $httpBackend.expectGET('/config').respond(200, {'googleAnalyticsAccount': 'something'});
}));

在您的测试中,当您需要模拟的 http 来回答时,您将调用httpBackend.flush(). 这就是我们引用它的原因,因此您不需要在每个测试中都注入它。

请注意,您需要加载 angular-mock.js 才能使其工作。

于 2013-03-26T18:10:34.103 回答