如何在 angular 中对状态转换进行单元测试?
How to unit test statetransition in angular?
我正在用 karma 进行单元测试。我想检查状态转换,所以我创建了这个测试。该应用程序从进入 landing
状态开始,然后我想从那里进入 main
。这是一条安全路线,因此被重定向到 login
:
it('should go to loginpage before main', function () {
$scope.$apply();
expect($state.current.name).toBe('landing');
$state.transitionTo('main');
$scope.$apply();
expect($state.current.name).toBe('login');
});
在我的 app.js 我有:
$rootScope.$on('$stateChangeStart', function (event,next) {
console.log('statechange from:', $state.current.name)
//console.log('statechange to:',$state)
if (!next.authenticate) {
return;
}
//if next state is secure then check whether user is logged in:
if (next.authenticate) {
event.preventDefault();
$state.transitionTo('login');
console.log('goto login');
}
});
当我 运行 我的业力测试时,我得到:
Chrome 51.0.2704 (Mac OS X 10.11.4) secure tests should go to loginpage before main FAILED
Expected '' to be 'landing'.
at Object.<anonymous> (/Users/dimitri/karma/basic_karma/appSpec.js:23:37)
Expected '' to be 'login'.
为什么 $state.current.name
是空的?
github 参考:https://github.com/dimitri-a/basic_karma
您似乎在尝试测试两种不同的东西。首先,您要测试 $stateChangeStart
事件是否被触发。其次,如果需要时重定向,您正在测试自定义处理程序和其中的逻辑。
单元测试是关于测试应用程序的一小部分。 $stateChangeStart
-事件不是您的应用程序的一部分,因为它是 ui-路由器组件的一部分。测试此事件是否触发不是您的责任。更好; ui-router 制作了自己的测试用例,用于检查 $stateChangeStart
是否被触发。您可以自己查看它们 right here。您可以相当确定事件会在需要时触发。
那么,我们如何测试您自己的自定义逻辑?首先,我们需要重构 $rootScope.$on
处理程序。
$rootScope.$on('$stateChangeStart', handleStateChange);
function handleStateChange(event, next) {
console.log('statechange from:', $state.current.name)
//console.log('statechange to:',$state)
if (!next.authenticate) {
return;
}
//if next state is secure then check whether user is logged in:
if (next.authenticate) {
event.preventDefault();
$state.transitionTo('login');
console.log('goto login');
}
}
这样,我们将您的自定义逻辑与 Angular $rootScope
分离,我们可以自行测试逻辑。别担心,当状态即将改变时,你的逻辑仍然运行。
接下来是测试本身。我们不必处理 $state.transitionTo
因为我们没有测试应用程序的那部分(同样,ui-router 有它自己的 $state.transitionTo
测试)。我们甚至不需要使用 $scope.$apply
.
describe('handleStateChange()', function() {
var $state;
beforeEach(inject(function(_$state_) {
$state = _$state_;
// we spy on the $state.transitionTo method, to check if it
// has been called by our test case.
spyOn($state, 'transitionTo');
}));
it('should transition to login state when authenticate:true', function () {
// arrange
var next = {
name: 'main',
authenticate: true
};
// act
handleStateChange({}, next);
// assert
// in case of authenticate: true, $state.transitionTo should
// have been called with the 'login' name
expect($state.transitionTo).toHaveBeenCalledWith('login');
});
it('should not transition to login state when authenticate:false', function () {
// arrange
var next = {
name: 'landing',
authenticate: false
};
// act
handleStateChange({}, next);
// assert
expect($state.transitionTo).not.toHaveBeenCalledWith('login');
});
});
我正在用 karma 进行单元测试。我想检查状态转换,所以我创建了这个测试。该应用程序从进入 landing
状态开始,然后我想从那里进入 main
。这是一条安全路线,因此被重定向到 login
:
it('should go to loginpage before main', function () {
$scope.$apply();
expect($state.current.name).toBe('landing');
$state.transitionTo('main');
$scope.$apply();
expect($state.current.name).toBe('login');
});
在我的 app.js 我有:
$rootScope.$on('$stateChangeStart', function (event,next) {
console.log('statechange from:', $state.current.name)
//console.log('statechange to:',$state)
if (!next.authenticate) {
return;
}
//if next state is secure then check whether user is logged in:
if (next.authenticate) {
event.preventDefault();
$state.transitionTo('login');
console.log('goto login');
}
});
当我 运行 我的业力测试时,我得到:
Chrome 51.0.2704 (Mac OS X 10.11.4) secure tests should go to loginpage before main FAILED
Expected '' to be 'landing'.
at Object.<anonymous> (/Users/dimitri/karma/basic_karma/appSpec.js:23:37)
Expected '' to be 'login'.
为什么 $state.current.name
是空的?
github 参考:https://github.com/dimitri-a/basic_karma
您似乎在尝试测试两种不同的东西。首先,您要测试 $stateChangeStart
事件是否被触发。其次,如果需要时重定向,您正在测试自定义处理程序和其中的逻辑。
单元测试是关于测试应用程序的一小部分。 $stateChangeStart
-事件不是您的应用程序的一部分,因为它是 ui-路由器组件的一部分。测试此事件是否触发不是您的责任。更好; ui-router 制作了自己的测试用例,用于检查 $stateChangeStart
是否被触发。您可以自己查看它们 right here。您可以相当确定事件会在需要时触发。
那么,我们如何测试您自己的自定义逻辑?首先,我们需要重构 $rootScope.$on
处理程序。
$rootScope.$on('$stateChangeStart', handleStateChange);
function handleStateChange(event, next) {
console.log('statechange from:', $state.current.name)
//console.log('statechange to:',$state)
if (!next.authenticate) {
return;
}
//if next state is secure then check whether user is logged in:
if (next.authenticate) {
event.preventDefault();
$state.transitionTo('login');
console.log('goto login');
}
}
这样,我们将您的自定义逻辑与 Angular $rootScope
分离,我们可以自行测试逻辑。别担心,当状态即将改变时,你的逻辑仍然运行。
接下来是测试本身。我们不必处理 $state.transitionTo
因为我们没有测试应用程序的那部分(同样,ui-router 有它自己的 $state.transitionTo
测试)。我们甚至不需要使用 $scope.$apply
.
describe('handleStateChange()', function() {
var $state;
beforeEach(inject(function(_$state_) {
$state = _$state_;
// we spy on the $state.transitionTo method, to check if it
// has been called by our test case.
spyOn($state, 'transitionTo');
}));
it('should transition to login state when authenticate:true', function () {
// arrange
var next = {
name: 'main',
authenticate: true
};
// act
handleStateChange({}, next);
// assert
// in case of authenticate: true, $state.transitionTo should
// have been called with the 'login' name
expect($state.transitionTo).toHaveBeenCalledWith('login');
});
it('should not transition to login state when authenticate:false', function () {
// arrange
var next = {
name: 'landing',
authenticate: false
};
// act
handleStateChange({}, next);
// assert
expect($state.transitionTo).not.toHaveBeenCalledWith('login');
});
});