在Angularjs中基于unit testing承诺的代码
我正在尝试在Angularjs中testing基于承诺的代码。
我在我的控制器中有以下代码:
$scope.markAsDone = function(taskId) { tasksService.removeAndGetNext(taskId).then(function(nextTask) { goTo(nextTask); }) }; function goTo(nextTask) { $location.path(...); }
我想unit testing下列情况:
- 当
markAsDone
被调用时,它应该调用tasksService.removeAndGetNext
- 当
tasksService.removeAndGetNext
完成时,它应该改变位置(调用goTo
)
在我看来,没有简单的方法来分别testing这两种情况。
我所做的testing第一个是:
var noopPromise= {then: function() {}} spyOn(tasksService, 'removeAndGetNext').andReturn(noopPromise);
现在来testing第二种情况,我需要创build另一个假的承诺,将永远resolved
。 这是非常乏味的,这是很多的样板代码。
有没有其他方法来testing这样的事情? 或者我的devise味道?
您仍然需要模拟服务并返回一个承诺,但是您应该使用真正的承诺,所以您不需要实现其function。 使用beforeEach
创build已经履行的承诺,并嘲笑服务,如果你需要它始终得到解决。
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); }));
如果你宁愿在每一个块中使用不同的值来解决这个问题,那么你只要将延期的内容暴露给一个局部variables,并在规范中解决它。
当然,你会保持你的testing,但是这里有一些非常简单的规范来告诉你它是如何工作的。
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'); });
另一种方法是直接从我正在testing的控制器中取出:
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; } }; };
作为又一个选项,您可以避免使用Q库( https://github.com/kriskowal/q )作为$q
的插入replace来调用$digest
,例如:
beforeEach(function () { module('Module', function ($provide) { $provide.value('$q', Q); }); });
这种承诺可以在$ digest循环之外解决/拒绝。