javascript 在使用 AngularJS 运行的应用程序中加载内容时进行单元测试

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15643517/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 01:31:09  来源:igfitidea点击:

Unit test when loading things at app run with AngularJS

javascriptangularjs

提问by arnaud.breton

I need my app to run some configuration at runtime vi an HTTP endpoint.

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

I wrote a simple service to do that:

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

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

Next, I call this module in a run block of my app module:

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

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

All is working well when the app is running but in my unit tests, I get this error: "Error: Unexpected request: GET /config"

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

I know what it means but I don't know how to mock it when it happens from a run block.

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

Thanks for your help

谢谢你的帮助

EDIT to add spec

编辑以添加规范

Calling this before each

在每个之前调用这个

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

Tried this to mock $httpBackend:

试过这个来模拟 $httpBackend:

beforeEach(inject(function($httpBackend) {

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

    angular.mock.module('app')

    $httpBackend.flush();
}));

But got:

但得到:

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)

EDIT since update to AngularJS 1.0.6

编辑自更新到 AngularJS 1.0.6

Since I've updated to AngularJS 1.0.6, advised by Igor from the Angular team, the issue is gone but now I've now got this one, which sounds more "normal" but I still can't figure out how to make it works.

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

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

回答by kylewelsby

I struggled with this error for a little while, but managed to come up with an sensible solution.

我在这个错误上挣扎了一段时间,但设法想出了一个明智的解决方案。

What I wanted to achieve is to successfully stub the Service and force a response, on controllers it was possible to use $httpBackendwith a request stub or exception before initiating the controller. In app.run()when you load the moduleit initialises the object and it's connected Services etc.

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

I managed to stub the Service using the following example.

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

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

});

I hope this helps your app.run()testing in the future.

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

回答by drcocoa

I don't know if you are still looking for an answer to this question. But here is some information that might help.

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

$injector is a singleton for an application and not for a module. However, angular.injector will actually try to create a new injector for each module (I suppose you have a

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

beforeEach(module("app")); 

at the beginning.

一开始。

I had the same problem while using Angular, RequireJS, Karma and Jasmine and I figured out two ways to solve it. I created a provider for the injector function as a separate dependency in my tests. For example MyInjectorProvider which provides a singleton instance of $injector.

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

The other way was to move the following statements:

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

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

inside the test suite description. So here is how it looked before:

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

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(){...});
    });
});

After applying the fix it looks like this:

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

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(){...});
    });
});

Both the solutions worked in my case.

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

回答by Caio Cunha

You should mock every HTTP request with ngMock.$httpBackend. Also, here is a guide.

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



Update

更新

You don't need the angular.mock.modulething, just need to inject your app module. Something like this:

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

var httpBackend;

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

In your tests, when you need the mocked http to answer, you will call httpBackend.flush(). This is why we have a reference to it, so you don't need to inject it in every single test you have.

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

Note you will need to load angular-mock.js in order to it work.

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