非同期処理をテストするための動作するコード。
TypeScriptでMocha/Chaiを使ったテストを書こうとして、非同期処理の結果をテストするのに苦労したので、動作したコードをシンプルにして書き残しておきます。
実行環境
今回の環境のpackage.jsonの抜粋します。
"dependencies": {
"@types/chai": "^4.2.11",
"@types/mocha": "^7.0.2",
"@types/node": "^14.0.13",
"chai": "^4.2.0",
"mocha": "^8.0.1",
"ts-node": "^8.10.2",
"typescript": "^3.9.5"
}
テストの終了時のthenやcatchでdone()を呼んで結果を報告するパターン。
- テストコードではpromiseはリターンしない。
- テストパスでdone(<falsey値>), テスト失敗でdone(<falsey以外の値>)を呼ぶことで結果を報告する。
- thenでパスのパターンと、catchでパスの2パターンをサンプルにした。
describe("非同期テスト 1 - done()で結果を報告。", () => {
it(`promise will be resolved 1000ms later`, (done) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("timed out");
}, 1000);
});
promise
.then((v) => {
expect(v).equal("timed out");
done();
})
.catch((e) => {
done("TEST FAILED");
});
});
it(`promise will be rejected 1000ms later`, (done) => {
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
reject("timed out");
}, 1000);
});
promise
.then(() => {
done("TEST FAILED");
})
.catch((e) => {
expect(e).to.equal("timed out");
done();
});
});
});
ちゃんと想定通りの結果になります。
非同期テスト 1 - done()で結果を報告。
✓ promise will be resolved 1000ms later (1005ms)
✓ promise will be rejected 1000ms later (1000ms)
テスト内でawaitにより非同期処理の終了を待つパターン。
- テストコードでpromiseはリターンしない。
- テストコードでdoneは呼ばない。
- assertやexpectで結果を検証・報告する。
- try節が成功してパスのケースと、catch節が実行されてパスとなる2ケースをサンプルにした。
describe("非同期テスト 2 - awaitで待つ", () => {
it(`await for 1000ms. awaiting success.`, async () => {
try {
const v = await timerToResolve();
expect(v).to.equal("timed out");
} catch (e) {
assert.fail();
}
});
it(`await for 1000ms. awaiting exception.`, async () => {
try {
await timerToReject();
assert.fail();
} catch (e) {
expect(e).to.equal("timed out");
}
});
});
// 1秒後にresolveされるpromiseを返す関数。
function timerToResolve():Promise<string> {
return new Promise((resolve, reject) => {
setInterval(() => {
resolve("timed out");
}, 1000);
});
}
// 1秒後にrejectされるpromiseを返す関数。
function timerToReject():Promise<string> {
return new Promise((resolve, reject) => {
setInterval(() => {
reject("timed out");
}, 1000);
});
}
こちらも想定通りの結果になります。
非同期テスト 2 - awaitで待つ
✓ await for 1000ms. awaiting success. (1002ms)
✓ await for 1000ms. awaiting exception. (1002ms)
テストコードがpromiseを返すパターン。
- テストコードでpromiseをリターンする。
- テストコードでdoneは呼ばない。
- 返すpromiseの中でthenやcatchの中で、assertやexpectで結果を検証・報告する。
escribe("非同期テスト 3 - promiseを返す", () => {
it(`should resolve the promise.`, () => {
return timerToResolve().then((v) => {
expect(v).equals("timed out");
}).catch(() => {
assert.fail();
});
});
it(`should reject the promise.`, () => {
return timerToReject().then(() => {
assert.fail();
}).catch((e) => {
expect(e).equals("timed out");
});
});
});
結果です。
非同期テスト 3 - promiseを返す
✓ should resolve the promise. (1009ms)
✓ should reject the promise. (1002ms)