我在angularjs中学习单元测试,并试图测试我的身份验证控制器。
目前,测试失败了Expected Function to equal '/dashboard'
。该测试似乎没有从我所知道的User.login
进入。
控制器:
angular.module('foo').controller('LoginCtrl',function($scope, $rootScope, $http, $window, $location, User){
$scope.submit = function () {
User.login($scope.user,
function (user) { // Success
$window.sessionStorage.token = user.id;
$scope.message = 'Welcome';
// Redirect to dashboard
$location.path('/dashboard');
},
function (err) {
console.log(err);
// handle login errors
$scope.message = 'Error: Invalid user or password';
}
);
};
});
测试:
describe('LoginCtrl', function() {
beforeEach(module('foo'));
var scope, ctrl, location, window, user;
beforeEach(inject(function($rootScope, $controller, $location, $window, User) {
scope = $rootScope.$new();
location = $location;
window = $window;
user = User;
ctrl = $controller('LoginCtrl', {$scope: scope, User: user});
}));
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
scope.submit();
console.log('message = '+scope.message);
console.log('after path = '+location.path());
console.log(window.sessionStorage.getItem('token'));
expect(location.path).toEqual('/dashboard');
});
});
**编辑**
User.login代码:
module.factory(
"User",
['LoopBackResource', 'LoopBackAuth', '$injector', function(Resource, LoopBackAuth, $injector) {
var R = Resource(
urlBase + "/users/:id",
{ 'id': '@id' },
{
"login": {
url: urlBase + "/users/login",
method: "POST",
interceptor: {
response: function(response) {
var accessToken = response.data;
LoopBackAuth.currentUserId = accessToken.userId;
LoopBackAuth.accessTokenId = accessToken.id;
LoopBackAuth.rememberMe = response.config.params.rememberMe !== false;
LoopBackAuth.save();
return response.resource;
}
}
}
});
答案 0 :(得分:2)
预期功能等于'/ dashboard'
测试运行器告诉你它需要一个字符串'/dashboard'
,而是获得一个函数的引用。那是因为location.path
是对函数的引用。试试这个:
expect(location.path()).toEqual('/dashboard');
答案 1 :(得分:2)
您的User.login
函数必须调用回调方法异步,因此当您致电scope.submit();
时,您的回调函数尚未调用 = >测试失败。
要测试此逻辑,您必须模拟User.login
函数:
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
//user here is user = User; in your beforeEach. I avoid pasting too much code.
//Jasmine 1.3: andCallFake
//Jasmine 2.0: and.callFake
spyOn(user, "login").andCallFake(function(userData,successCallback){
successCallback(userData); //simulate the success case.
}); //mock your User.login
scope.submit();
console.log('message = '+scope.message);
console.log('after path = '+location.path());
console.log(window.sessionStorage.getItem('token'));
expect(location.path()).toEqual('/dashboard'); //fix the problem with location.path
});
<强>解释强>:
spyOn(user, "login").andCallFake
用我们的假函数替换实际函数。
在此测试用例中,您正在测试should redirect upon successful login
,因此前提是登录必须成功,通过模拟登录功能,我们可以确保此前提条件为在测试中总是为真。
您可以类似地测试类似于set error message when login failed
的案例,为了对此进行测试,您需要确保测试中的前置条件login failed
始终为true :
it('should redirect upon successful login', function() {
console.log('before path = '+location.path());
scope.user = {
"username": "my_user",
"password": "my_pass"
};
//user here is user = User; in your beforeEach. I avoid pasting too much code.
//Jasmine 1.3: andCallFake
//Jasmine 2.0: and.callFake
spyOn(user, "login").andCallFake(function(userData,successCallback,errorCallback){
errorCallback(userData); //simulate the error case.
}); //mock your User.login
scope.submit();
expect(scope.message).toEqual('Error: Invalid user or password'); //verify that the message was set correctly.
});