【问题标题】:AngularJS Unit Testing - Various patterns for injecting dependenciesAngularJS 单元测试 - 注入依赖项的各种模式
【发布时间】:2015-09-15 09:06:25
【问题描述】:

我是单元测试的新手,主要从我找到的示例中学习。问题是我见过太多不同的模式,很难理解它们之间的区别。以及如何为各种用例组合这些模式。下面是一种这样的模式:

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

因此,从这个模式中,我发现 Angular 核心服务/提供者应该使用下划线模式注入,而其他 3rd 方依赖项或我自己的依赖项应该使用 $injector.get() 模式完成。这是有效的吗?我注意到我可以使用 Angular 核心服务执行 $injector.get() 并且它仍然可以工作,所以也许这样做只是惯例?另外,beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html')); 中的“security/loginModal.tpl.html”有什么意义?我知道这是一个添加到模板缓存中的 HTML 模板,但是 angular.mock.module 用它做什么?

我还看到了这种不太常见的模式,它在上述逻辑中引发了活动:

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

如果我可以像这段代码对 $location 所做的那样向注入回调添加服务,那似乎是一种更简单的引用依赖项的方法。为什么我不应该这样做?

这是另一种模式:

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

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

据我了解,此模式的重点是使用模拟的 $window 初始化“security.service”模块。这是有道理的,但是我如何使这种模式与以前的模式相适应?即如何模拟“security/loginModal.tpl.html”,如何注入我的 Angular 核心依赖项 + 我的其他依赖项?

最后,我可以和不能在嵌套描述中注入什么并且它会阻塞?假设我不能将模拟服务重新注入到我正在测试的模块中是否安全。那么我可以注入什么以及用例是什么?

如果有帮助回答这些问题的 AngularJS 单元测试初始化​​的权威文档来源,请指出它。

【问题讨论】:

    标签: angularjs unit-testing jasmine karma-jasmine


    【解决方案1】:

    我发现 Angular 核心服务/提供者应该使用下划线模式注入,而其他 3rd 方依赖项或我自己的依赖项应该使用 $injector.get() 模式完成

    你可以使用任何一个。 下划线 模式只是一种方便的方法,可以避免与同名的局部变量发生冲突。考虑以下

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

    如果我可以像这段代码对 $location 所做的那样向注入回调添加服务,那似乎是一种更简单的引用依赖项的方法。为什么我不应该这样做?

    你应该:)


    另外,beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html')); 中的“security/loginModal.tpl.html”有什么意义?

    据我所知,除非您有一个具有该名称的实际模块,例如

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

    这将失败。 angular.mock.module 只能传递模块名称、实例或匿名初始化函数。


    我如何模拟 'security/loginModal.tpl.html'

    理想情况下,您不应该这样做。单元测试应该测试代码的 API...交互点,通常由对象上可公开访问的方法和属性定义。

    如果您只是想阻止 Karma 尝试通过 HTTP 加载模板(通常来自指令测试),您可以使用模板预处理器,例如 karma-ng-html2js-preprocessor


    最后,我可以和不能在嵌套描述中注入什么并且它会阻塞?假设我不能将模拟服务重新注入到我正在测试的模块中是否安全。那么我可以注入什么以及用例是什么?

    您几乎可以在任何地方运行angular.mock.inject(通常是beforeEachit)。模拟服务应仅在模块或匿名模块初始化函数中配置(如在您的示例中使用 $provide$window)并且通常您自己的模块之后(即“security.service ") 以便通过在注入器中替换它们来覆盖真实的服务。一旦你运行了inject(),你就不能追溯性地用模拟替换服务。

    【讨论】:

    • 谢谢!我现在更好地理解了这一切。
    猜你喜欢
    • 1970-01-01
    • 2021-06-19
    • 1970-01-01
    • 2018-01-11
    • 2017-04-01
    • 1970-01-01
    • 2013-04-11
    相关资源
    最近更新 更多