如何对 AngularJS 服务/工厂进行单元测试
How to unit test an AngularJS service / factory
我已经使用 AngularJS 进行开发了一段时间,我写的东西也很有效,但我知道我已经到了想要 运行 单元测试的地步我的 AngularJS 代码。
我创建了一个非常简单的服务,可以将样式表注入页面,
请参阅下面的示例代码:
var OfficeSuiteStylesheetInjectorModule = angular.module('OfficeSuiteStylesheetInjectorModule', []);
OfficeSuiteStylesheetInjectorModule.factory('stylesheetInjectorService', ['$q', function($q) {
// Returns the service itself.
return {
inject: function(id, uri) {
var deferred = $q.defer();
// Embed the stylesheet into the page, but only when it's non-existing.
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
{
link.onload = deferred.resolve;
angular.element('head').append(link);
}
return deferred.promise;
}
}
}
}]);
这不是一个大服务,它只是依赖于 $q
的承诺,这样当样式表嵌入到页面中时我可以 运行 额外的逻辑。
现在,我正在使用 Jasmine(我对此很陌生)来测试我的 JavaScript 代码,我想测试这个模块。
我有骨架:
// Tests for the angular 'StylesheetInjectorService'.
describe('StylesheetInjectorService', function() {
var stylesheetInjectorService = {};
// This code is executed before every test.
beforeEach(function() {
// Tells jamine that the module we're working on is the 'OfficeSuiteStylesheetInjectorModule'.
angular.module('OfficeSuiteStylesheetInjectorModule');
});
// Ensures that it injects a stylesheet element into the page.
it('Should inject a stylesheet element into the page.', function() {
// How to test here that the stylesheet is injected?
});
});
});
如何在页面中注入服务并确保加载样式表?
编辑:加载服务现在有效:
beforeEach(module('OfficeSuiteStylesheetInjectorModule'));
// This code is executed before every test.
beforeEach(function() {
// Inject the required dependencies into the page.
inject(function($injector) {
stylesheetInjectorService = $injector.get('stylesheetInjectorService');
});
});
同样的问题仍然悬而未决。如何测试页面中是否嵌入了样式表?
非常感谢任何帮助。
亲切的问候
我刚才也有这个疑惑。
要将控制器和服务注入到测试中,您需要使用一个名为 Angular Mocks. Here's some official reference 的工具。
我建议您将它与 Karma 环境一起使用。
这是一个很棒的入门教程:
https://www.airpair.com/angularjs/posts/unit-testing-angularjs-applications
This other one 适用于 Ionic 框架,但仍然适用于您的情况
希望对您有所帮助。
要编写将样式表附加到 angular.element('head')
的规范,我会稍微更改逻辑以将其附加到 $document.head
。
If you dont want to do that, I would recommend that you change your service into a directive
seeing as how injecting a script element, is manipulating the DOM. That way you would kill two birds with one stone, as you would need to inject $compile
to test your directive (which would enable you to $compile a custom head
element to boot). But this is slightly "over the top" for now.
实施:
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
link.onload = deferred.resolve;
$document.head.append(link);
return deferred.promise;
}
}
每个之前:
/**
* Sorry, this was previously $location which was just
* such a silly mistake.
*/
var $timeout;
beforeEach(function () {
inject(function ($injector) {
$timeout = $injector.get('$timeout');
});
});
它:
it('attaches the stylesheet to $document.head', function () {
styleSheetInjectorService.inject('someId', '/path/to/some/stylesheet');
$timeout.flush(); // flush promises
expect(angular.element($document.head).lastChild[0].nodeName).to.eq('LINK');
});
沿着这些路线的东西应该让你起来 运行。请记住,我编写的规范使用 chai#expect style assertions, and the mocha 测试框架。如果你想复制粘贴,请编辑语法以适应 Jasmine。
我已经使用 AngularJS 进行开发了一段时间,我写的东西也很有效,但我知道我已经到了想要 运行 单元测试的地步我的 AngularJS 代码。
我创建了一个非常简单的服务,可以将样式表注入页面, 请参阅下面的示例代码:
var OfficeSuiteStylesheetInjectorModule = angular.module('OfficeSuiteStylesheetInjectorModule', []);
OfficeSuiteStylesheetInjectorModule.factory('stylesheetInjectorService', ['$q', function($q) {
// Returns the service itself.
return {
inject: function(id, uri) {
var deferred = $q.defer();
// Embed the stylesheet into the page, but only when it's non-existing.
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
{
link.onload = deferred.resolve;
angular.element('head').append(link);
}
return deferred.promise;
}
}
}
}]);
这不是一个大服务,它只是依赖于 $q
的承诺,这样当样式表嵌入到页面中时我可以 运行 额外的逻辑。
现在,我正在使用 Jasmine(我对此很陌生)来测试我的 JavaScript 代码,我想测试这个模块。
我有骨架:
// Tests for the angular 'StylesheetInjectorService'.
describe('StylesheetInjectorService', function() {
var stylesheetInjectorService = {};
// This code is executed before every test.
beforeEach(function() {
// Tells jamine that the module we're working on is the 'OfficeSuiteStylesheetInjectorModule'.
angular.module('OfficeSuiteStylesheetInjectorModule');
});
// Ensures that it injects a stylesheet element into the page.
it('Should inject a stylesheet element into the page.', function() {
// How to test here that the stylesheet is injected?
});
});
});
如何在页面中注入服务并确保加载样式表?
编辑:加载服务现在有效:
beforeEach(module('OfficeSuiteStylesheetInjectorModule'));
// This code is executed before every test.
beforeEach(function() {
// Inject the required dependencies into the page.
inject(function($injector) {
stylesheetInjectorService = $injector.get('stylesheetInjectorService');
});
});
同样的问题仍然悬而未决。如何测试页面中是否嵌入了样式表?
非常感谢任何帮助。
亲切的问候
我刚才也有这个疑惑。 要将控制器和服务注入到测试中,您需要使用一个名为 Angular Mocks. Here's some official reference 的工具。
我建议您将它与 Karma 环境一起使用。
这是一个很棒的入门教程:
https://www.airpair.com/angularjs/posts/unit-testing-angularjs-applications
This other one 适用于 Ionic 框架,但仍然适用于您的情况
希望对您有所帮助。
要编写将样式表附加到 angular.element('head')
的规范,我会稍微更改逻辑以将其附加到 $document.head
。
If you dont want to do that, I would recommend that you change your service into a
directive
seeing as how injecting a script element, is manipulating the DOM. That way you would kill two birds with one stone, as you would need to inject$compile
to test your directive (which would enable you to $compile a customhead
element to boot). But this is slightly "over the top" for now.
实施:
if (!angular.element('#' + id).length) {
var link = StylesheetFactory.Create(id, uri);
link.onload = deferred.resolve;
$document.head.append(link);
return deferred.promise;
}
}
每个之前:
/**
* Sorry, this was previously $location which was just
* such a silly mistake.
*/
var $timeout;
beforeEach(function () {
inject(function ($injector) {
$timeout = $injector.get('$timeout');
});
});
它:
it('attaches the stylesheet to $document.head', function () {
styleSheetInjectorService.inject('someId', '/path/to/some/stylesheet');
$timeout.flush(); // flush promises
expect(angular.element($document.head).lastChild[0].nodeName).to.eq('LINK');
});
沿着这些路线的东西应该让你起来 运行。请记住,我编写的规范使用 chai#expect style assertions, and the mocha 测试框架。如果你想复制粘贴,请编辑语法以适应 Jasmine。