jestでTypeORMのテストを作った時の知見
jest で TypeORM のテストを作った時の知見を紹介します。
基本的な考え
まず大事なことは、jest で DB を含めた TypeORM のテストをするべきではなく、モックを使ってドメインのテストをした方が遥かに効果的です。 jest はテストケースをパラレルに動作するため、DB を含めたテストをすると、テストケース A で入れたデータをテストケース B が読んでしまうことがあり得ます。 そのため、テストケースが複雑で、意図が明確にならない可能性があります。
jest は設定によってシリアルに動作させることもできますが、テスト自体が遅くなってしまうのは致命的な問題だと思います。 じゃあ、トランザクションで管理すればいいじゃないかと思うのだが、現状の TypeORM は save のタイミングでコミットをするため、 テストケースごとにトランザクションを貼って制御しようという考えは忘れるべきだと思います。
※ただし、CircleCI は --runInBand
を推奨しているのでシリアルにしか動かない。悩ましい
細かなテクニック
それでも DB を含めたテストをしなければならない場合のために、2つのテクニックを紹介します。
- テストデータが汚染されていることを想定したテストを書く
テストで検証するべき動作をテストが汚染されていることを想定して書くべきです。 例えば、データをインサートするメソッドでは、データがインサートされている数ではなく、そのデータがインサートされたかどうかを検証するべきです。
// テストしたいこと
const created = repository.save(entity);
const stored = repository.findAll();
// これは良くない
expect(stored).toHaveLength(1);
// こういうテストをするべき
expect(stored.some(entity => entity.id === created.id)).toBe(true);
- テスト開始前に wait を入れてテストをずらす
複数のテーブルを変更するテストケースはなるべく最後にやるようにすると良いでしょう。
そのために、beforeAll
で wait 処理を入れてテストの実行自体を遅らせると良いでしょう。
beforeAll(async () => {
await new Promise(resolve => {
setTimeout(() => resolve(), 800);
});
});
``
くれぐれもこの沼に足を踏み込んではいけない。