我正试图用Jasmine测试我的AngularJS控制器,使用Karma。但一个在现实生活中运行良好的$timeout
却破坏了我的测试。
控制器:
var Ctrl = function($scope, $timeout) {
$scope.doStuff = function() {
$timeout(function() {
$scope.stuffDone = true;
}, 250);
};
};
Jasmine it块(其中$scope
和控制器已正确初始化):
it('should do stuff', function() {
runs(function() {
$scope.doStuff();
});
waitsFor(function() {
return $scope.stuffDone;
}, 'Stuff should be done', 750);
runs(function() {
expect($scope.stuffDone).toBeTruthy();
});
});
当我在浏览器中运行我的应用程序时,$timeout
函数将被执行,$scope.stuffDone
将为true。但在我的测试中,$timeout
什么都不做,函数从未执行过,Jasmine在超时750毫秒后报告错误。这里可能出了什么问题?
根据$timeout的Angular JS文档,可以使用$timeout.flush()
同步刷新延迟函数的队列。
尝试将您的测试更新为:
it('should do stuff', function() {
expect($scope.stuffDone).toBeFalsy();
$scope.doStuff();
expect($scope.stuffDone).toBeFalsy();
$timeout.flush();
expect($scope.stuffDone).toBeTruthy();
});
这是一个显示你的原始测试失败和新测试通过的plunker。
正如其中一条评论中所指出的,Jasmine setTimeout
mock没有被使用,因为使用的是angular的JS mock $timeout
服务。就我个人而言,我宁愿使用Jasmine的,因为它的嘲讽方法可以让我测试超时的长度。您可以在单元测试中使用一个简单的提供者来有效地规避它:
module(function($provide) {
$provide.constant('$timeout', setTimeout);
});
注意:如果你走这条路,一定要在茉莉花之后打$scope.apply()
。Clock.tick.
由于$timeout
只是window.setTimeout
的包装器,您可以使用模仿window.setTimeout
的jasmine Clock.useMock()
beforeEach(function() {
jasmine.Clock.useMock();
});
it('should do stuff', function() {
$scope.doStuff();
jasmine.Clock.tick(251);
expect($scope.stuffDone).toBeTruthy();
});