Angularjs中基于单元测试承诺的代码

Mic*_*zka 67 javascript promise angularjs

我很难尝试在Angularjs中测试基于promise的代码.

我的控制器中有以下代码:

    $scope.markAsDone = function(taskId) {
        tasksService.removeAndGetNext(taskId).then(function(nextTask) {
            goTo(nextTask);
        })
    };

    function goTo(nextTask) {
        $location.path(...);
    }
Run Code Online (Sandbox Code Playgroud)

我想对以下情况进行单元测试:

  • 什么时候markAsDone叫它应该打电话tasksService.removeAndGetNext
  • 什么时候tasksService.removeAndGetNext完成它应该改变位置(调用goTo)

在我看来,没有简单的方法来分别测试这两个案例.

我测试第一个测试的是:

var noopPromise= {then: function() {}}
spyOn(tasksService, 'removeAndGetNext').andReturn(noopPromise);
Run Code Online (Sandbox Code Playgroud)

现在要测试第二种情况,我需要创建另一个永远的假承诺resolved.这一切都非常乏味,而且它是很多样板代码.

有没有其他方法来测试这样的东西?或者我的设计闻到了什么?

Cai*_*nha 107

您仍然需要模拟服务并返回一个承诺,但您应该使用真正的承诺,因此您不需要实现其功能.使用beforeEach创建已被兑现承诺,并嘲笑服务,如果你需要它总是被解决.

var $rootScope;

beforeEach(inject(function(_$rootScope_, $q) {
  $rootScope = _$rootScope_;

  var deferred = $q.defer();
  deferred.resolve('somevalue'); //  always resolved, you can do it from your spec

  // jasmine 2.0
  spyOn(tasksService, 'removeAndGetNext').and.returnValue(deferred.promise); 

  // jasmine 1.3
  //spyOn(tasksService, 'removeAndGetNext').andReturn(deferred.promise); 

}));
Run Code Online (Sandbox Code Playgroud)

如果您更愿意it使用不同的值在每个块中解析它,那么您只需将延迟公开给局部变量并在规范中解析它.

当然,你会保持你的测试,但这里有一些非常简单的规范,告诉你它是如何工作的.

it ('should test receive the fulfilled promise', function() {
  var result;

  tasksService.removeAndGetNext().then(function(returnFromPromise) {
    result = returnFromPromise;
  });

  $rootScope.$apply(); // promises are resolved/dispatched only on next $digest cycle
  expect(result).toBe('somevalue');
});
Run Code Online (Sandbox Code Playgroud)

  • +1我错过了这个$ rootScope.$ apply() - 非常有帮助谢谢 (13认同)
  • 对于记录,整个`var deferred = $ q.defer(); deferred.resolve( '东西'); returnValue(deferred.promise)`可以简化为`returnValue($ q.when('something'))` (3认同)
  • 我正在做的是注入`$ rootScope`(如果你之前和之后插入_,它将被忽略)并通过局部变量公开它.这样你就不需要将它注入每个单独的规范中,因为所有这些都可能会使用它. (2认同)