单元测试的承诺为基础的代码Angularjs(Unit-test promise-based cod

2019-08-31 11:54发布

我有困难的时候试图Angularjs测试基于承诺的代码。

我在我的控制器下面的代码:

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

    function goTo(nextTask) {
        $location.path(...);
    }

我想单元测试以下情况:

  • markAsDone被称为它应该调用tasksService.removeAndGetNext
  • tasksService.removeAndGetNext做它应该改变位置(调用goTo

在我看来,有单独测试这两个例无简便的方法。

我所做的测试,第一次是:

var noopPromise= {then: function() {}}
spyOn(tasksService, 'removeAndGetNext').andReturn(noopPromise);

现在来测试第二种情况下我需要创建另一个虚假的承诺,将永远resolved 。 这一切都相当乏味,这是一个很大的样板代码。

是否有任何其他的方式来测试这样的事情? 抑或是我的设计嗅觉?

Answer 1:

您仍需要模拟服务,并返回一个承诺,但你应该用真正的承诺来代替,这样你就不会需要实现其功能。 使用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); 

}));

如果你宁愿喜欢解决它在每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');
});


Answer 2:

另一种方法是以下,取直出控制器我的测试:

var create_mock_promise_resolves = function (data) {
    return { then: function (resolve) { return resolve(data); };
};

var create_mock_promise_rejects = function (data) {
    return { then: function (resolve, reject) { if (typeof reject === 'function') { return resolve(data); } };
};

var create_noop_promise = function (data) {
    return { then: function () { return this; } };
};


Answer 3:

而作为另一种选择,你可不必调用$digest通过使用Q库( https://github.com/kriskowal/q )作为一个下拉更换为$q例如:

beforeEach(function () {
    module('Module', function ($provide) {
        $provide.value('$q', Q); 
    });
});

这样的承诺可以解决/拒绝$消化周期之外。



文章来源: Unit-test promise-based code in Angularjs