Promiseで逐次実行する時のテスト
var Promise = require('es6-promise').Promise; var tasks = { first: function(value) { return new Promise(function(resolve, reject) { if (value < 2) { resolve(value + 1); } else { reject(new Error('failed at first')); } }); }, second: function(value) { return new Promise(function(resolve, reject) { if (value % 2) { resolve(value + 1); } else { reject(new Error('failed at second')); } }); }, third: function(value) { return new Promise(function(resolve, reject) { resolve(value + 1); }); } }; var waterfall = function(value) { return Promise.resolve(value) .then(tasks.first) .then(tasks.second) .then(tasks.third); };
例えばこの関数waterfallが
場合のテストケースをそれぞれ用意したい。
いろいろ試した結果、こんな感じになった。
var assert = require("power-assert"); var sinon = require('sinon'); describe('waterfall', function() { beforeEach(function() { sinon.spy(tasks, 'second'); sinon.spy(tasks, 'third'); }); afterEach(function() { tasks.second.restore(); tasks.third.restore(); }); it('passed', function(done) { return waterfall(0).then(function(value) { assert(value === 3); }).then(done, done); }); it('failed at first', function(done) { return waterfall(2).then(function(value) { throw new Error(value); }, function(error) { assert(error.message === 'failed at first'); assert(tasks.second.notCalled); }).then(done, done); }); it('failed at second', function(done) { return waterfall(1).then(function(value) { throw new Error(value); }, function(error) { assert(error.message === 'failed at second'); assert(tasks.third.notCalled); }).then(done, done); }); });
最初はspy.calledBefore
とかで実行順序全部チェックしてたけど、それはPromise自体のテストになってしまうので
- 適切なエラーが投げられてる
- reject後の関数が呼ばれてない
ことがテストできてれば良いかなと。
前提条件として投げるエラーはそれぞれ個別のmessageじゃないとrejectされた箇所を探すのは難しそう。
chaiならhttps://github.com/domenic/chai-as-promisedとか使うとスマートに書けるかも。