インテグレーションテストとは?
インテグレーションテストは、各コンポーネントを隔離してテストするのではなく、2つ以上のコンポーネントが協調して正しく動くことを検証します。
ユニットテストは部品が動くことを証明し、インテグレーションテストは部品が噛み合うことを証明します。それらはモジュール間、サービス間、あるいはモジュールと実際のデータベースの間の継ぎ目を動かし、ユニットテストが意図的にmockで消し去る不整合を捕らえます。テストピラミッドの中間に位置します。
インテグレーションテストがカバーするもの
インテグレーションテストは、ユニットテストがstubで置き換える境界を越えます。実際のデータベースと会話する関数、メッセージを交換する2つのサービス、ストレージに到達するAPI層などです。それが捕らえるバグは、通常、2つの部品がどう相互作用するかについての誤った前提です。
実際の依存関係対フェイク
インテグレーションテストは、mockではなく、containerで立ち上げたデータベースのような実際または実際に近い依存関係をよく使います。その現実性が要点ですが、それはまたユニットテストよりも遅く、環境の問題を起こしやすくします。
実践例
レコードを保存して読み戻すテストは、ORM、query層、実際のデータベースを一緒に動かし、mockが隠すであろうschemaやシリアライゼーションの不整合を捕らえます。
test("saves and loads a user", async () => {
await repo.save({ id: 1, name: "Ada" });
const loaded = await repo.findById(1);
expect(loaded.name).toBe("Ada");
});なぜ重要か
- コンポーネント間の契約の不整合を捕らえます。
- 設定や環境の問題を早期に表面化させます。
- 配線されたシステムが動くという確信を与えます。
- ユニットテストより数は少ないですが、テストあたりの示唆は大きいです。
CIにおけるインテグレーションテスト
実際のサービスが必要なため、インテグレーションテストはパイプラインでservice containerとともに実行されることが多く、ユニットテストより時間がかかります。隔離されたrunnerで実行するとテスト間の干渉を避けられ、起動が遅かったcontainerのような本当に一時的な失敗を自動リトライすることでシグナルを綺麗に保てます。Latchkeyはこの層に適した、綺麗で隔離されたrunnerと一時的な失敗のリトライを提供します。
重要なポイント
- インテグレーションテストは、境界をまたいでコンポーネントが協調して動くことを検証します。
- mockより実際の依存関係を好み、速度と引き換えに現実性を得ます。
- ピラミッドの中間を占め、CIではユニットテストの後に実行されます。