使用 sinon returns promise 的函数对 angularJs 服务进行存根
Stubbing an angularJs service with a function that returns a promise using sinon
我正在尝试测试调用服务方法的控制器。服务方法 returns 一个承诺,控制器在调用服务方法后立即调用 .then()
内联。我正在尝试使用 sinon 存根该服务,而 Jasmine 不断抛出错误,指出 then
未定义且不是函数。
这是控制器:
var loginModalController = function ($scope, authenticationService) {
this.submit = submit;
function submit(user, password) {
$scope.email = user;
authenticationService.login(user, password)
.then(handleSuccessLogin, handleErrorLogin);
}
}
这是服务:
function authenticationService($http, $q, endPointService) {
var baseUri = endPointService.getApiEndpoint();
var service = {
getTermsAndConditions: getTermsAndConditions,
login: login,
acceptTerms: acceptTerms
};
return service;
function getTermsAndConditions() {
...
};
function login(user, password) {
var deferred = $q.defer();
$http({ method: 'POST', url: baseUri + '/api/tokens', data: { username: user, password: password } }).
success(function (data, status, headers, config) {
$http.defaults.headers.common.Authorization = 'Basic ' + data.EncryptedTokenId;
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
};
function acceptTerms() {
...
};
}
这是测试:
describe('loginModalController', function () {
var scope, loginModalController, authenticationServiceMock, localSaverServiceMock;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(function () {
module('clientAppModule');
inject(function ($rootScope, $controller, authenticationService, localSaverService) {
scope = $rootScope.$new();
authenticationServiceMock = sinon.stub(authenticationService)
.login.returns({ then: function () { return loginInformationMock } });
localSaverServiceMock = sinon.stub(localSaverService);
loginModalController = $controller('loginModalController', {
$scope: scope,
$state: {},
authenticationService: authenticationServiceMock,
errorCodes: {},
localSaverService: localSaverServiceMock
});
});
});
it('should login', function () {
loginModalController.submit("test", "test");
});
});
我的代码有四个问题:
- 我不必要地使用 Sinon
- 我使用的是
stub()
的 return 值,而不是让它存根服务。
- 我没有使用
$q
到 return 延迟承诺来匹配登录功能。
- 我需要在作用域上调用
$digest()
以获得延迟承诺,以便在断言之前解决。
所以这是固定的测试代码:
beforeEach(module('clientAppModule'));
describe('loginModalController', function () {
var scope, authenticationService, localSaverService;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(inject(function ($injector, $rootScope, $controller, $q) {
scope = $rootScope.$new();
scope.$close = function () { };
authenticationService = $injector.get('authenticationService');
localSaverService = $injector.get('localSaverService');
spyOn(authenticationService, 'login').and.callFake(function () {
var deferred = $q.defer();
deferred.resolve(loginInformationMock);
return deferred.promise;
});
spyOn(localSaverService, 'saveLoginInformation').and.stub();
$controller('loginModalController', {
$scope: scope,
$rootScope: {},
$state: {},
authenticationService: authenticationService,
errorCodes: {},
localSaverService: localSaverService
});
}));
it('should call login on authenticationService', function () {
// Arrange
// Act
scope.submit("test", "test");
// Assert
expect(authenticationService.login).toHaveBeenCalled();
});
it('should save login info after successful login', function () {
// Arrange
// Act
scope.submit("test", "test");
scope.$digest();
// Assert
expect(localSaverService.saveLoginInformation).toHaveBeenCalled();
});
});
我正在尝试测试调用服务方法的控制器。服务方法 returns 一个承诺,控制器在调用服务方法后立即调用 .then()
内联。我正在尝试使用 sinon 存根该服务,而 Jasmine 不断抛出错误,指出 then
未定义且不是函数。
这是控制器:
var loginModalController = function ($scope, authenticationService) {
this.submit = submit;
function submit(user, password) {
$scope.email = user;
authenticationService.login(user, password)
.then(handleSuccessLogin, handleErrorLogin);
}
}
这是服务:
function authenticationService($http, $q, endPointService) {
var baseUri = endPointService.getApiEndpoint();
var service = {
getTermsAndConditions: getTermsAndConditions,
login: login,
acceptTerms: acceptTerms
};
return service;
function getTermsAndConditions() {
...
};
function login(user, password) {
var deferred = $q.defer();
$http({ method: 'POST', url: baseUri + '/api/tokens', data: { username: user, password: password } }).
success(function (data, status, headers, config) {
$http.defaults.headers.common.Authorization = 'Basic ' + data.EncryptedTokenId;
deferred.resolve(data);
}).
error(function (data, status, headers, config) {
deferred.reject(status);
});
return deferred.promise;
};
function acceptTerms() {
...
};
}
这是测试:
describe('loginModalController', function () {
var scope, loginModalController, authenticationServiceMock, localSaverServiceMock;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(function () {
module('clientAppModule');
inject(function ($rootScope, $controller, authenticationService, localSaverService) {
scope = $rootScope.$new();
authenticationServiceMock = sinon.stub(authenticationService)
.login.returns({ then: function () { return loginInformationMock } });
localSaverServiceMock = sinon.stub(localSaverService);
loginModalController = $controller('loginModalController', {
$scope: scope,
$state: {},
authenticationService: authenticationServiceMock,
errorCodes: {},
localSaverService: localSaverServiceMock
});
});
});
it('should login', function () {
loginModalController.submit("test", "test");
});
});
我的代码有四个问题:
- 我不必要地使用 Sinon
- 我使用的是
stub()
的 return 值,而不是让它存根服务。 - 我没有使用
$q
到 return 延迟承诺来匹配登录功能。 - 我需要在作用域上调用
$digest()
以获得延迟承诺,以便在断言之前解决。
所以这是固定的测试代码:
beforeEach(module('clientAppModule'));
describe('loginModalController', function () {
var scope, authenticationService, localSaverService;
var loginInformationMock = { 'firstName': 'Testuser' };
beforeEach(inject(function ($injector, $rootScope, $controller, $q) {
scope = $rootScope.$new();
scope.$close = function () { };
authenticationService = $injector.get('authenticationService');
localSaverService = $injector.get('localSaverService');
spyOn(authenticationService, 'login').and.callFake(function () {
var deferred = $q.defer();
deferred.resolve(loginInformationMock);
return deferred.promise;
});
spyOn(localSaverService, 'saveLoginInformation').and.stub();
$controller('loginModalController', {
$scope: scope,
$rootScope: {},
$state: {},
authenticationService: authenticationService,
errorCodes: {},
localSaverService: localSaverService
});
}));
it('should call login on authenticationService', function () {
// Arrange
// Act
scope.submit("test", "test");
// Assert
expect(authenticationService.login).toHaveBeenCalled();
});
it('should save login info after successful login', function () {
// Arrange
// Act
scope.submit("test", "test");
scope.$digest();
// Assert
expect(localSaverService.saveLoginInformation).toHaveBeenCalled();
});
});