我开始为我的Angular应用程序进行单元测试,我对如何实际构建测试文件夹有一些疑问。我基本上使用了yeoman角度生成器,因此它预先配置了Jasmine和Karma。
这是我尝试测试的场景......
我有一个" PageHeaderDirective"它显示用户的姓名和电子邮件(如欢迎信息)以及注销链接。页眉指令的代码是无关紧要的,但我确实需要点击" / user"来自后端的端点以获取用户的详细信息。以下是UserService的代码,它注入了PageHeaderDirective:
/**
* @ngdoc function
* @name Common.service.UserService
* @description
* Service to retrieve a {@link User} from the backend.
*/
(function () {
'use strict';
angular.module('Common').service('UserService', UserService);
UserService.$inject = ['User', 'Restangular'];
/**
* User service function.
* @param User The {@link User} provider.
* @param Restangular The restangular provider.
*/
function UserService(User, Restangular) {
var userPromise;
return {
getUser: getUser
};
/**
* Retrieves a {@link User} instance from the /user endpoint.
* @returns A promise to be resolved with a {@link User} instance.
*/
function getUser() {
if(!userPromise) {
userPromise = Restangular.one('user').get().then(function(data) {
return User.factory(data);
});
}
return userPromise;
}
}
})();
这是一个非常简单的PageHeaderDirective测试:
describe('Pageheader Tests', function() {
'use strict';
var scope;
var element;
beforeEach(module('templates'));
beforeEach(module('Common'));
beforeEach(inject(function(_$rootScope_, $compile) {
scope = _$rootScope_.$new();
scope.message = 'Test message';
element = '<ft-page-header message="message" page="home"></ft-page-header>';
element = $compile(element)(scope);
scope.$digest();
}));
it('should render a page header with the logo and username', function() {
expect(element.find('.logo-text').length).toBe(1);
var isolateScope = element.isolateScope();
expect(isolateScope.name).toBe('test');
});
});
现在,你可能会说,我收到了一个未知的提供商错误&#34;未知提供商:RestangularProvider&lt; - Restangular&lt; - UserService&lt; - pageHeaderDirective&#34;因为我没有把它注入测试中。
我已经读过您可以在每个测试文件中执行beforeEach(function(){ module(function($provide) { $provide.service('UserService', function() { ... }})});
之类的操作,但是在指令/控制器使用UserService的任何时候我都不想这样做。如何从每个测试文件中删除该部分并将其放入自己的&#34; UserService.mock.js&#34;文件?如果可能,我将如何注入&#34; UserService.mock.js&#34;进入我的测试?
其次,我还将Restangular注入PageHeaderDirective以注销用户(Restangular.one('logout').get().then...
)。我如何模仿这个(我不想调用API端点)?
最后,如果我正在注入其他提供程序($ document,$ localStorage,$ window),我是否还需要将所有这些注入到测试中?如果是这样,怎么样?
谢谢!
答案 0 :(得分:4)
如果有人想要做我已经做过的事情(将你的模拟分成不同的文件,这样你就不需要复制粘贴很多东西了),这就是我发现的。
// /test/mock/UserService.mock.js
(function() {
"use strict";
angular.module('mocks.Common').service('UserService', mock);
mock.$inject = ['$q', 'User'];
function mock($q, User) {
return {
getUser : getUser
};
function getUser() {
return $q.when(User.factory({
firstName: 'test',
email: 'test@gmail.com',
id: 1
}));
}
}
})();
首先,您需要确保创建了您的模块(在本例中我创建了“mocks.Common”)。在一个单独的文件中,我把这行:angular.module('mocks.Common', []);
这创建了我的“mocks.Common”模块。然后,我创建了一个名为“UserService”的模拟器,并使用$ q返回带有一些虚拟数据的promise。 User.factory
部分只是我公共模块中真实应用程序中的工厂函数。
如果您拥有上述模拟的“UserService”,请确保在测试设置期间以正确的顺序注入模块。像这样:
module('app');
module('templates');
module('mocks.Common');
现在,当我的测试运行时,PageHeaderDirective将使用模拟的“UserService”而不是真实的!“
至于我的第二个问题:我还没有真正完成它,但我相信我将能够使用$ httpBackend来测试任何Restangular功能。
第三,我发现如果你只是在所有测试中运行module('appName')
,你应该自动获得任何所需的依赖项。例如,这是我整个应用程序的模块定义:
angular.module('app', [
'Common',
'ngAnimate',
'ngCookies',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
'ngDialog',
'ngStorage',
'lodash',
'smart-table',
'rhombus',
'helpers',
'restangular',
'moment',
'cgBusy',
'duScroll'
])
所以当我module('app')
时,我会在测试中自动获得所有这些依赖项(注意我的应用配置中的“公共”依赖)。