AngularJS 单元测试 - 注入依赖项的各种模式
AngularJS Unit Testing - Various patterns for injecting dependencies
我是单元测试的新手,主要是从我找到的示例中学习。问题是我见过太多不同的模式,以至于很难理解它们之间的区别。以及如何针对各种用例组合这些模式。下面是一个这样的模式:
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 核心 services/providers 应该使用下划线模式注入,而其他第 3 方依赖项或我自己的依赖项应该使用 $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 核心依赖项 + 我的其他依赖项?
最后,我可以和不能在嵌套的 describe 和 it 块中注入什么?可以安全地假设我不能向我正在测试的模块重新注入模拟服务吗?那么我可以注入什么以及用例是什么?
如果 AngularJS 单元测试初始化有明确的文档来源可以帮助回答这些问题,请指出。
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
你可以使用任何一个。 下划线 模式只是一种避免与同名局部变量发生冲突的便捷方法。考虑以下
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?
你应该:)
Also, what is the point of 'security/loginModal.tpl.html' in beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html'));
?
据我所知,除非你有同名的实际模块,例如
angular.module('security/loginModal.tpl.html', [])
这会失败。 angular.mock.module
只应传递模块名称、实例或匿名初始化函数。
how do I mock 'security/loginModal.tpl.html'
理想情况下,您不应该这样做。单元测试应该测试代码的 API...交互点,通常由对象上可公开访问的方法和属性定义。
如果您只是想阻止 Karma 尝试通过 HTTP 加载模板(通常来自指令测试),您可以使用像 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?
您可以 运行 angular.mock.inject
几乎任何地方(通常是 beforeEach
和 it
)。模拟服务只应在模块或匿名模块初始化函数中配置(如您使用 $provide
和 $window
的示例),通常 在 您自己的模块之后)(即 "security.service"),以便通过在注入器中替换真实服务来覆盖它们。一旦你 运行 inject()
,你就不能用模拟来追溯替换服务。
我是单元测试的新手,主要是从我找到的示例中学习。问题是我见过太多不同的模式,以至于很难理解它们之间的区别。以及如何针对各种用例组合这些模式。下面是一个这样的模式:
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 核心 services/providers 应该使用下划线模式注入,而其他第 3 方依赖项或我自己的依赖项应该使用 $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 核心依赖项 + 我的其他依赖项?
最后,我可以和不能在嵌套的 describe 和 it 块中注入什么?可以安全地假设我不能向我正在测试的模块重新注入模拟服务吗?那么我可以注入什么以及用例是什么?
如果 AngularJS 单元测试初始化有明确的文档来源可以帮助回答这些问题,请指出。
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
你可以使用任何一个。 下划线 模式只是一种避免与同名局部变量发生冲突的便捷方法。考虑以下
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?
你应该:)
Also, what is the point of 'security/loginModal.tpl.html' in
beforeEach(angular.mock.module('security.service', 'security/loginModal.tpl.html'));
?
据我所知,除非你有同名的实际模块,例如
angular.module('security/loginModal.tpl.html', [])
这会失败。 angular.mock.module
只应传递模块名称、实例或匿名初始化函数。
how do I mock 'security/loginModal.tpl.html'
理想情况下,您不应该这样做。单元测试应该测试代码的 API...交互点,通常由对象上可公开访问的方法和属性定义。
如果您只是想阻止 Karma 尝试通过 HTTP 加载模板(通常来自指令测试),您可以使用像 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?
您可以 运行 angular.mock.inject
几乎任何地方(通常是 beforeEach
和 it
)。模拟服务只应在模块或匿名模块初始化函数中配置(如您使用 $provide
和 $window
的示例),通常 在 您自己的模块之后)(即 "security.service"),以便通过在注入器中替换真实服务来覆盖它们。一旦你 运行 inject()
,你就不能用模拟来追溯替换服务。