我正在使用yeoman generator创建的应用程序,并在业力中进行测试。
我的每个服务都有可重复使用的模拟对象。 我如何正确地用模拟替换特定的服务依赖,所以我可以使用jasmine来监视方法
到目前为止,我这样做了:
我的服务:
angular.module('ql')
.service('loginService', ['$http','API','authService', function ($http, API, authService) {
return {
//service implementation
}]);
模拟authService:
'use strict';
//lets mock http auth service, so it would be spied upon.
ql.mock.$authServiceMockProvider = function() {
this.$get = function() {
var $service = {
loginConfirmed: function() { }
};
return $service;
};
};
//and register it.
angular.module('qlMock').provider({
$authServiceMock: ql.mock.$authServiceMockProvider
});
我的测试:
'use strict';
describe('When i call login method()', function () {
// load the service's module
beforeEach(module('ql'));
beforeEach(angular.mock.module('qlMock'));
// instantiate service
var loginService,
authService,
$httpBackend;
beforeEach(function() {
// replace auth service with a mock.
// this seems kind of dirty... is there a bettery way?
module(function($provide, $injector){
authService = $injector.get('$authServiceMockProvider').$get();
$provide.value('authService', authService);
});
//actually get the loginService
/*jshint camelcase: false */
inject(function(_loginService_, _$httpBackend_) {
loginService = _loginService_;
$httpBackend =_$httpBackend_;
});
//http auth module method, that should be call only on success scenarios
spyOn(authService, 'loginConfirmed').andCallThrough();
});
it('it should do something', function () {
//actual test logic
});
});
我不喜欢的是这条线:
authService = $injector.get('$authServiceMockProvider').$get();
我想简单地以某种方式获取authServiceMock(没有获取提供者,并调用et方法),然后将其注入loginService。
我知道我可以简单地将我的$ authServiceMock称为authService,并将其作为模拟提供,以便它始终覆盖我的默认实现,但我不想这样做。
答案 0 :(得分:15)
我知道这已经晚了但也许会帮助那些发生在这篇文章上的人。
使用Angular的$provide服务在Jasmine中模拟服务非常简单。诀窍是在注入服务之前使用$ provide来交换服务实现。
例如,假设我们正在测试使用$location服务获取有关当前URL的信息的服务。
// load the service's module under test
beforeEach(module('myExampleModule'));
// mock out $location with a fake one
beforeEach(module(function ($provide) {
//create mock impl
var mockLocation = {
path: function(){
return '/somewhere'
}
}
$provide.value('$location', mockLocation); // use $provide to swap the real $location with our mock
}));
var $location;
// inject dependencies ($location will be our mocked $location)
beforeEach(inject(function (_$location_) {
$location = _$location_;
}));
it('should return mock url', function(){
var path = $location.path();
expect(path).toBe('/somewhere'); //Assert that $location.path() returns '/somewhere'
});
答案 1 :(得分:0)
我想我会简单地使用角度服务装饰器来模拟或完全替换您的测试服务。 Here is an example
答案 2 :(得分:0)
我从来没有在服务中对服务进行过单元测试,但不管怎么说,我们的验证/登录工作很快就会出现。
当您对loginService进行单元测试时,您只对服务与AuthService提供的数据交互的方式感兴趣,而不是AuthService正常工作。这是你在模拟中设置的。
我认为这将是我的方法:(在父母描述中)
var
loginService,
authService
AUTH_DATA
;
beforeEach(function() {
module('ql');
// I am assuming this is the global app module so both services live here? If not include this module as well
});
beforeEach(inject(function (_authService_, _loginService_) {
authService = _authService_;
loginService = _loginService_;
//Now with the spy setup you intercept the calls to the service and you choose what data to return, based on the unit test. Now your LoginService can simply resond to the data it is give from the login service
}));
it('it should do something', function () {
spyOn(authService, 'loginConfirmed').andReturn(AUTH_DATA);
loginService.confirmLogin(); //Dont know your actual API but a contrived guess
expect('something to happen in loginservice when AUTH_DATA is returned').toBe('Something else')
});