AngularJS$timeout函数在我的Jasmine规范中没有执行



我正试图用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();
  });

最新更新