2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScript + Mocha/Chai 非同期テストコードメモ

Last updated at Posted at 2020-06-21

非同期処理をテストするための動作するコード。

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)
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?