Skip to content
Latchkey

コントラクトテストとは?

コントラクトテストは、2つのサービスが交換するメッセージの形式について合意しているかを、両方を同時に起動せずに検証します。

サービス同士が通信するとき、一方の変更がもう一方を静かに壊してしまうことがあります。コントラクトテストは、合意されたリクエストとレスポンスの形式をコントラクトとして捉え、各サイドをそれに対して独立して検証することで、これを防ぎます。完全なエンドツーエンドテストのコストをかけずに統合の信頼性を得られます。

コンシューマー・プロバイダーモデル

コンシューマーはプロバイダーに期待するものを定義します。どのフィールドを送信し、どれを返してほしいかです。その期待がコントラクトになります。次にプロバイダーは、コントラクトを満たしていることを証明するために独自のテストを実行します。どちらのサイドも、相手がライブで動いている必要はありません。

なぜ統合テストだけではだめなのか

多くのサービスにまたがる完全な統合テストは遅く、壊れやすく、調整が難しいものです。特に各チームが独立してdeployする場合はなおさらです。コントラクトテストは、最も一般的な破壊、つまり互換性のないAPI変更を、はるかに早く高速に、各サイドがそれぞれのpipelineで検出します。

簡単な例

コンシューマーコントラクトは、/users/1へのGETがidとnameを持つオブジェクトを返さなければならないと宣言し、プロバイダーテストは実際のエンドポイントがその形式を守っていることを検証します。

A consumer expectation
expect(response).toMatchContract({
  id: "number",
  name: "string",
});

コントラクトテストが適している場面

  • マイクロサービスやAPI駆動のアーキテクチャ。
  • サービスを独立してdeployするチーム。
  • 破壊的な変更がstagingに到達する前に検出すること。
  • いくつかの実際のE2Eテストを置き換えるのではなく補完すること。

CIにおけるコントラクトテスト

各サービスは自身のpipelineでコントラクトテストを実行するため、システム全体を起動する必要がなく、検証は高速で並列化可能です。プロバイダーとコンシューマーのチェックを高速で隔離されたrunner上で実行することで、サービス数が増えてもチーム間のフィードバックを迅速に保てます。

重要なポイント

  • コントラクトテストは、サービスがメッセージの形式について合意しているかを確認します。
  • 各サイドはコントラクトを独立して検証し、完全な統合は不要です。
  • 破壊的なAPI変更を早期に検出し、CIで高速に実行できます。

関連ガイド