SmartBear Pactflow: コントラクト テストとは? 使うべき理由

毎週、Pact の Slack チャネルには、「テストが失敗します。助けてください。」や「チームを説得するのを手伝ってください。」など、多数の質問が寄せられます。以下はその一例です。


説得してください!

コントラクト テストの利点については別の記事で紹介しました。この記事では、よくある質問「コントラクト テストとは? なぜマイクロサービスのテストに採用すべきか?」に答えるため、次のトピックについて説明します。

  1. 統合テストとは? E2E 統合テストにおける課題
  2. コントラクト テストとは? なぜそれが役立つのか?
  3. Pact の仕組み
  4. Pact を使ったコントラクト テストのデモ

統合テストとは?

コントラクト テストについて説明する前に、コントラクト テストがなぜ存在するのかについてお話したほうが良いでしょう。コントラクト テストは統合テストを補完します。統合テストとは、システム全体が適切に機能することを確認するプロセスです。

分散システムにおいて、統合テストは、マイクロサービス、Web アプリケーション、モバイル アプリケーションなど、リモートで通信するさまざまなコンポーネントがすべて連携して動作することを検証します。

統合テストには多くの種類がありますが、最もよく使われているのは「エンドツーエンド (E2E) 統合テスト」と呼ばれるものアプローチで、すべてのコンポーネントを実際の環境 (本番環境に近いもの) にデプロイし、一連のテスト シナリオを実行します。

コントラクト テストの概念は Pact よりも古いものですが、Pact が誕生したのは、E2E 統合テストが不完全であるからです。

E2E 統合テストにおける課題

E2E 統合テストにおける課題 [5:39]

ピラミッドの最上層に位置するテストは、顧客の体験をより忠実に再現する一方で、次のような欠点があります。

  • 時間がかかる: 複数のシステムを横断し、一般に連続して実行する必要があるため、各テストが完了するまでに数秒から数分かかります。さらに、前提条件となる設定 (データの準備など) を行う必要がある場合は、追加の時間がかかります。
  • 保守が困難: E2E テストでは、実行前にすべてのシステムが、バージョンとデータを含め、適切な状態である必要があります。
  • 不安定または信頼性が低い: テスト環境の構築は複雑であるため、しばしば失敗し、偽陽性 (false-positive) を引き起こす可能性があり、チームの負担が増します。多くの場合、コードの変更とは関係のない設定の問題で失敗します。
  • 修正が困難: E2E テストが失敗した場合、分散とリモートという性質上、問題のデバッグは通常困難です。
  • 拡張性に乏しい: 多くのチームのコードをテストするようになると、テストがより複雑になり、テスト スイートの実行速度が指数関数的に低下し、自動化パイプラインがリリースの妨げになります。
  • 不具合の発見が遅れる: テスト スイートの実行が複雑なため、多くの場合、これらのテストはコードがコミットされた後に CI 上でのみ実行され、コミットから数日後に別のテストチームによって実行されることも少なくありません。フィードバックの遅れは、現代のアジャイル デリバリー チームにとって大きな負担となります。

このような課題があるため、主要な業務や機能を確実にカバーするには、E2E 統合テストに含めるコンポーネントの数を最小限に抑えることが推奨されます。

詳細は、「E2E テストは不完全」を参照してください。

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

コントラクト テストの説明と PACT の仕組み [10:30]

コントラクト テストは、2 つの別々のシステム (2 つのマイクロサービスなど) に互換性があり、互いに通信できることを保証します。各サービス間のインタラクションをキャプチャして「コントラクト」に格納し、それを使って両者がコントラクトに従っているかどうかを検証します。コントラクト テストはスキーマ テストを超えるもので、両者が許容されるインタラクションのセットについて合意することを要求し、時間の経過とともに進化することを可能にします。

このテスト形式が、同じことを目的とする他のアプローチと異なる点は、各システムを独立してテストできることと、コントラクトがコード自体によって生成され、常に現実に即して更新されることです。

次の図は、コントラクト テストの主要なステップを表しています。


コントラクト テストの仕組み

この他にも、コントラクト テストには多くの重要な性質があります。以降で詳しく説明します。

Pact でコントラクト テストを実装する方法

Pact はコードファーストのコントラクト テスト ツールで、統合ポイントの両側のコードにアクセスする必要があります。Pact テストを作成するには、コンシューマーのユニット テストを作成し、プロバイダー側で状態を操作 (通常はユニット テストのコンテキスト内で) できる必要があります。

Pactflow でコントラクト テストを実装する方法

Pactflow は主要なコントラクト テスト ツールとして Pact をサポートしていますが、Postman、Dredd、その他のサービス仮想化ツールやモッキング ツールなど、幅広いツールをコントラクト テスト プロセスで使用できるようにし、それらを一般的なコントラクト テスト機能に「アップグレード」することも可能です。詳細は、双方向のコントラクト テストに関するブログを参照してください。

コンシューマー主導型コントラクト テストとは?

「コンシューマー主導型」とは、マイクロサービスの内部設計が API のコンシューマー寄りであることを表します。プロバイダー主導動型 API は、公開されるデータとそれを公開するシステム寄りです。

Pact と Spring Cloud Contract は、コンシューマー主導型の実装をデフォルトとするフレームワークです。どちらもコントラクト テストの主要な利点を得るための要件ではなく、コントラクト テストの目的を達成するために使用できます。

コントラクト テストの利点

テスト ピラミッドにおけるコントラクト テストの位置付けと、E2E 統合テストを排除する方法 [6:26]

最初に、テスト自動化アプローチにおける、コントラクト テストの位置付けについて考えてみましょう。テスト自動化戦略を検討する際、どのように取り組むべきかの良い経験則として、Mike Cohn 氏の「テスト ピラミッド」で提唱されているアプローチが役立ちます。

健全で、高速で、メンテナンス可能なテスト スイートを作成するには、ピラミッド型になるように、多数の小さくて高速なユニット テストと、いくつかのより粗い粒度のテストと、アプリケーションの隅から隅までをテストする少数の高レベルのテストを作成します[3]。


出典: 実用的なテスト ピラミッド

コントラクト テストは、高速に実行され、外部システムと統合する必要がないため、ピラミッドの「サービス テスト」層に適合します。このテストの役割は、リリース前に、統合するシステムがコードと互換性があることを確実にします。

注: このピラミッドの頂点に位置する「UI テスト」は、しばしば「E2E 統合テスト」とも呼ばれます。

コントラクト テストの価値

コントラクト テストは、一般的に E2E 統合テストとは逆の性質を持っています。

  • 高速: 複数のシステムとやり取りする必要がないため、高速に動作します。
  • 保守が容易: テストを作成するためにエコシステム全体を理解する必要はありません。
  • デバッグと修正が容易: テスト対象のコンポーネントでのみ問題が発生するため、通常は失敗した行番号や特定の API エンドポイントを取得します。
  • 再現性がある。
  • 拡張性がある: 各コンポーネントを独立してテストできるため、ビルド パイプラインにかかる時間は直線的または指数関数的に増加しません。
  • ローカルで不具合を発見: 開発者のマシン上で不具合を発見できます。コントラクト テストは、コードをプッシュする前に開発者のマシンで実行することが可能であり、そうすべきです。

ビジネスの観点からは、不具合の発見がプロジェクト ライフサイクルの後のほうになるほど、その修正にコストがかかることはよく知られています。


Beth Skurrie 氏による講演資料ビデオ [45:53]

自動テストのほとんどを高速なユニット テストまたはローカル統合テストとして実行することで、ビルド速度を最低限に抑え、チーム内でキューが溜まるのを防ぐことができます。

さらに、コントラクト テストは、副次的な利点をもたらすことが分かっています。

その他の利点

  • API より先にコンシューマー (たとえば React Web App) を開発できます。
  • プロバイダー要件を最初に把握することで、プロバイダーに必要なものだけを正確に実装できます。
  • プロバイダーの用途が明確に文書化されます (「~の場合、~に対するリクエストは、~を返す」)。
  • 各コンシューマーがどのフィールドに興味があるかを正確に把握できるため、コンシューマーに影響を与えることなく、未使用のフィールドを削除したり、プロバイダー API に新しいフィールドを追加することが可能です。
  • プロバイダー API に変更があった場合、どのコンシューマーが壊れるかを即座に確認できます。

この記事では、コントラクト テストにより E2E 統合テストの多く (場合によってはすべて) を置き換えて、CI パイプラインをスピードアップし、チームの生産性を高める方法を紹介しました。

コントラクト テストは万能ではなく、テスト要件はチームによって異なります。そのため、テスト戦略の適用方法と目的 (どのような結果を得るべきか) についてよく検討してください。

Pact と Pactflow を使用したコントラクト テストの例

NodeJS と Pact JS を使用したコントラクト テストのデモ [16:26]

Pactflow 製品に関するお問い合わせは、こちら


この資料は、Pactflow の Web サイトで公開されている「What is contract testing and why should I try it?」の日本語参考訳です。