AngularJS单元测试 - 对注入依赖各种图案 [英] AngularJS Unit Testing - Various patterns for injecting dependencies

查看:128
本文介绍了AngularJS单元测试 - 对注入依赖各种图案的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是新来的单元测试和我主要是我发现的例子学习。问题是,我见过这么多不同的模式,这是很难理解的差异,它们之间是什么。以及如何将这些模式结合起来,各​​种用例。下面就是这样的一个模式:

 变量$ rootScope,$窗口,$位置;
    beforeEach(angular.mock.module('security.service','安全/ loginModal.tpl.html'));    beforeEach(注(功能(_ $ rootScope_,_ $位置指定:){
        $ rootScope = _ $ rootScope_;
        $位置= _ $位置指定:;
    }));    VAR服务,排队;
    beforeEach(注入(函数($喷油器){
        服务= $ injector.get('安全');
        排队= $ injector.get('securityRetryQueue');
    }));

所以从这个模式,我已经收集了角的核心服务/供应商应与在其他第三方的依赖还是我自己的依赖应该使用$ injector.get()模式来完成下划线模式注入。这是有效的?我发现我可以做$ injector.get()与角核心服务,它仍然可以工作,所以也许这只是惯例做这样?此外,什么是安全性/ loginModal.tpl.html在 beforeEach(angular.mock.module('security.service','安全/ loginModal.tpl.html'))点; ?我知道,这是添加到模板缓存中的HTML模板,但什么是angular.mock.module用它做什么?

我也看到了,在上面的逻辑抛出一个扳手这种不太常见的模式:

  beforeEach(注(函数($喷油器,_ $位置指定:){
        安全= $ injector.get('安全');
        $位置= _ $位置指定:;
    }));

如果我可以再补充服务,以注入回调像这样code确实有$位置,这似乎是引用依赖一个简单的方法。我为什么不这样做呢?

下面是另一种模式:

  beforeEach(函数(){
        模块('security.service',函数($提供){
            $ provide.value('$窗口',$窗口= jasmine.createSpyObj('$窗口',['的addEventListener','postMessage的','开放']));
        });        注(功能(安全){
            服务=安全;
        });
    });

从我的理解,这种模式的关键是要初始化一个嘲讽$窗口security.service模块。这是有道理的,但我怎么与previous模式符合这种模式呢?即我怎么嘲笑的安全/ loginModal.tpl.html',我怎么注入我的角度依赖核心+我的其他依赖?

最后,我能和不能注入嵌套描述和它阻止?它是安全的假设,我不能复古注入嘲笑服务,我测试的模块。这样的话我可以注入和用例是什么?

如果有对AngularJS单元测试初始化​​一个最终文件来源,这将有助于回答这些问题,请点我吧。


解决方案

  

我已经收集了角的核心服务/供应商应与在其他第三方的依赖还是我自己的依赖应该用$ injector.get做下划线模式注入()模式


您可以使用。在下划线的模式仅仅是一个方便的方法,以避免与同名的局部变量冲突。考虑以下

 变量$ rootScope,为myService,HTTP; //这些是局部变量beforeEach(注(功能(_ $ rootScope_,_myService_,$ HTTP){
    $ rootScope = _ $ rootScope_; //强调避免变量名称冲突
    为myService = _myService_; //你的定制服务同样在这里
    HTTP = $ HTTP; //局部变量命名不同服务
}));


  

如果我可以再补充服务,以注入回调像这样code确实有$位置,这似乎是引用依赖一个简单的方法。我为什么不这样做呢?


您应该:​​)



  

此外,什么是安全性/ loginModal.tpl.html在 beforeEach(angular.mock.module('security.service'的地步,安全/ loginModal.tpl.html') );


据我所知,除非你有一个实际的模块使用该名称,例如:

  angular.module('安全/ loginModal.tpl.html',[])

这将失败。 angular.mock.module 只能通过模块名,实例或匿名的初始化功能。



  

我怎么嘲笑的安全/ loginModal.tpl.html


在理想情况下,你不应该。单元测试应该测试code的API ...互动点,通常都是通过对你的对象公开访问的方法和属性来定义。

如果你只是从试图加载在HTTP上的模板(通常从指令测试)试图prevent噶,你可以使用模板pre处理器一样的因缘-NG-html2js- preprocessor ​​



  

最后,我能和不能注入嵌套描述和它阻止?它是安全的假设,我不能复古注入嘲笑服务,我测试的模块。这样的话我可以注入和用例是什么?


您可以运行 angular.mock.inject 任何地方(一般 beforeEach )。嘲笑服务应只在一个模块或匿名模块初始化函数进行配置(如你的例子与 $提供 $窗口),并通常以由喷油器取代它们覆盖了真正的服务<后您自己的模块(S)(即security.service)STRONG>。一旦你运行注入(),你不能复古积极与模拟更换服务。

I'm new to unit testing and am mainly learning from examples that I find. The problem is that I've seen so many different patterns that it's hard to understand what the differences are between them. And how to combine those patterns for various use cases. Below is one such pattern:

    var $rootScope, $window, $location;
    beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html'));

    beforeEach(inject(function(_$rootScope_, _$location_) {
        $rootScope = _$rootScope_;
        $location = _$location_;
    }));

    var service, queue;
    beforeEach(inject(function($injector) {
        service = $injector.get('security');
        queue = $injector.get('securityRetryQueue');
    }));

So from this pattern, I've gleaned that Angular core services/providers should be injected with the underscore pattern where as other 3rd party dependencies or my own dependencies should be done using the $injector.get() pattern. Is this valid? I've noticed I can do $injector.get() with Angular core services and it will still work so maybe it's just convention to do it this way? Also, what is the point of 'security/loginModal.tpl.html' in beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html'));? I know that it is an HTML template added to the template cache but what is angular.mock.module doing with it?

I've also seen this less common pattern that throws a monkey wrench in the above logic:

    beforeEach(inject(function($injector, _$location_) {
        security = $injector.get('security');
        $location = _$location_;
    }));

If I can just add services to the inject callback like this code does with $location, that seems like a simpler way of referencing dependencies. Why should I not do this?

Here's another pattern:

    beforeEach(function() {
        module('security.service', function($provide) {
            $provide.value('$window', $window = jasmine.createSpyObj('$window', ['addEventListener', 'postMessage', 'open']));
        });

        inject(function(security) {
            service = security;
        });
    });

From my understanding, the point of this pattern is to initialize "security.service" module with a mocked $window. This makes sense, but how do I fit this pattern in with the previous patterns? i.e. how do I mock 'security/loginModal.tpl.html', how do I inject my Angular core dependencies + my other dependencies?

Lastly, what can I and can't inject in nested describe and it blocks? Is it safe to assume I can't retro-inject mocked services to the module I'm testing. So then what can I inject and what are the use cases?

If there is a definitive documentation source for AngularJS unit testing initialization that would help answer these questions, please point me to it.

解决方案

I've gleaned that Angular core services/providers should be injected with the underscore pattern where as other 3rd party dependencies or my own dependencies should be done using the $injector.get() pattern

You can use either. The underscore pattern is simply a convenience method to avoid conflicts with local variables of the same name. Consider the following

var $rootScope, myService, http; // these are local variables

beforeEach(inject(function(_$rootScope_, _myService_, $http) {
    $rootScope = _$rootScope_; // underscores to avoid variable name conflict
    myService = _myService_; // same here with your custom service
    http = $http; // local variable is named differently to service
}));

If I can just add services to the inject callback like this code does with $location, that seems like a simpler way of referencing dependencies. Why should I not do this?

You should :)


Also, what is the point of 'security/loginModal.tpl.html' in beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html'));?

As far as I know, unless you have an actual module with that name, eg

angular.module('security/loginModal.tpl.html', [])

this will fail. angular.mock.module should only be passed module names, instances or anonymous initialisation functions.


how do I mock 'security/loginModal.tpl.html'

Ideally, you shouldn't. Unit tests should test the API of your code... points of interaction, typically defined by publically accessible methods and properties on your objects.

If you're just trying to prevent Karma from attempting to load templates over HTTP (usually from directive tests), you can use a template pre-processor like karma-ng-html2js-preprocessor


Lastly, what can I and can't inject in nested describe and it blocks? Is it safe to assume I can't retro-inject mocked services to the module I'm testing. So then what can I inject and what are the use cases?

You can run angular.mock.inject just about anywhere (typically beforeEach and it). Mocked services should only be configured in a module or anonymous module initialisation function (as in your example with $provide and $window) and typically after your own module(s) (ie "security.service") in order to override the real services by replacing them in the injector. Once you've run inject(), you cannot retro-actively replace a service with a mock.

这篇关于AngularJS单元测试 - 对注入依赖各种图案的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆