私はAngularjsで約束ベースのコードをテストするのに苦労しています。
コントローラーに次のコードがあります。
$scope.markAsDone = function(taskId) {
tasksService.removeAndGetNext(taskId).then(function(nextTask) {
goTo(nextTask);
})
};
function goTo(nextTask) {
$location.path(...);
}
次のケースのユニットテストを行います。
markAsDone
が呼び出されると、tasksService.removeAndGetNext
を呼び出す必要がありますtasksService.removeAndGetNext
が完了したら、場所を変更する必要があります(goTo
を呼び出します)これらの2つのケースを個別にテストする簡単な方法はないと思われます。
最初のものをテストするために私がしたことは:
var noopPromise= {then: function() {}}
spyOn(tasksService, 'removeAndGetNext').andReturn(noopPromise);
次に、2番目のケースをテストするために、常にresolved
になる別の偽のプロミスを作成する必要があります。それはすべて非常に面倒であり、多くの定型コードです。
そのようなことをテストする他の方法はありますか?または、私のデザインは匂いがしますか?
それでもサービスをモックしてプロミスを返す必要がありますが、代わりに実際のプロミスを使用する必要があるため、その機能を実装する必要はありません。 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');
});
別のアプローチは、私がテストしていたコントローラーから直接取り出した次のものです。
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; } };
};
さらに別のオプションとして、$digest
のドロップイン置換としてQライブラリ( https://github.com/kriskowal/q )を使用して$q
byを呼び出す必要を回避できます。
beforeEach(function () {
module('Module', function ($provide) {
$provide.value('$q', Q);
});
});
このようにして、$ digestサイクル以外でプロミスを解決/拒否できます。