我正在尝试使用Karma使用Jasmine测试我的AngularJS控制器。但是$timeout
在现实生活中运作良好,会使我的测试崩溃。
控制器:
var Ctrl = function($scope, $timeout) {
$scope.doStuff = function() {
$timeout(function() {
$scope.stuffDone = true;
}, 250);
};
};
Jasmine阻止($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
将成立。但是在我的测试中,$timeout
什么也没做,函数永远不会被执行,并且Jasmine在超过750毫秒后报告错误。这可能有什么问题?
答案 0 :(得分:76)
根据$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,显示原始测试失败和新测试通过。
答案 1 :(得分:9)
正如其中一条评论中所述,Jasmine setTimeout
mock未被使用,因为使用了角度的JS模拟$timeout
服务。就个人而言,我宁愿使用Jasmine,因为它的模拟方法让我测试超时的长度。您可以在单元测试中使用简单的提供程序有效地规避它:
module(function($provide) {
$provide.constant('$timeout', setTimeout);
});
注意:如果你走这条路,请务必在jasmine.Clock.tick之后拨打$scope.apply()
。
答案 2 :(得分:4)
由于$timeout
只是window.setTimeout
的包装,您可以使用jasmines Clock.useMock()
来模仿window.setTimeout
beforeEach(function() {
jasmine.Clock.useMock();
});
it('should do stuff', function() {
$scope.doStuff();
jasmine.Clock.tick(251);
expect($scope.stuffDone).toBeTruthy();
});