契約テスト

契約テストは、消費者テストと提供者テストの二つの部分から成ります。消費者と提供者の関係の単純な例は、フロントエンドとバックエンドの間です。フロントエンドが消費者で、バックエンドが提供者です。フロントエンドはバックエンドが提供するAPIを消費します。テストは、この両者が合意された契約に従っていることを保証し、契約から逸脱した場合は、意味のある会話をトリガーして、変更をすり抜けるのを防ぎます。

コンシューマテストはユニットテストに似ており、それぞれの仕様でリクエストと期待されるモックレスポンスを定義し、それらの定義に基づいてコントラクトを作成します。一方、プロバイダテストはインテグレーションテストに似ており、各仕様がコントラクトで定義されたリクエストを受け取り、実際のサービスに対してそのリクエストを実行します。

既存のコントラクトテストは、以下を参照してください:

今のところ、契約自体は/spec/contracts/contracts に保存されています。計画では、AWSでホストされているPactBrokerか、他の同様のサービスを使用する予定です。

テストを書く

消費者テストの実行

コンシューマテストを実行する前に、spec/contracts/consumer にアクセスしてnpm install を実行します。すべての消費者テストを実行するには、npm run jest:contract -- /specs を実行するだけです。また、特定の spec ファイルを実行する場合は、/specs を特定の spec ファイル名に置き換えてください。コンシューマテストを実行すると、プロバイダテストが実際の API の動作を検証するために使用するコントラクトが作成されます。

プロジェクトのルートディレクトリからyarn jest:contract というコマンドを使ってテストを実行することもできます。

プロバイダテストの実行

プロバイダテストを実行する前に、GDK(GitLab Development Kit)が完全にセットアップされ、実行されていることを確認してください。GDKリポジトリに詳細なセットアップ手順があります。プロバイダテストを実行するには、./lib/tasks/contractsにある Rake タスクを使います。プロバイダーテストに関連するすべての Rake タスクのリストを取得するには、bundle exec rake -T contracts を実行してください。例えば

$ bundle exec rake -T contracts
rake contracts:merge_requests:pact:verify:diffs_batch                                   # Verify provider against the consumer pacts for diffs_batch
rake contracts:merge_requests:pact:verify:diffs_metadata                                # Verify provider against the consumer pacts for diffs_metadata
rake contracts:merge_requests:pact:verify:discussions                                   # Verify provider against the consumer pacts for discussions
rake contracts:merge_requests:test:merge_requests[contract_merge_requests]              # Run all merge request contract tests

Pact Broker での契約の検証

デフォルトでは、Rakeタスクはローカルに保存されたコントラクトを検証します。Pact Broker で発行されたコントラクトを検証するには、PACT_BROKER 環境変数をtrue に設定し、QA_PACT_BROKER_HOST を Pact Broker の URL に設定する必要があります。ここで重要なことは、プロバイダーテストのファイルパスとファイル名は、Pact Broker でコントラクトを見つけるために使用されるものであり、プロバイダーテストの命名規則に従っていることを確認することが重要であるということです。

Pact Broker へのコントラクトの発行

QA_PACT_BROKER_HOST 環境変数を設定し、publish-contracts.sh スクリプトを実行することで、コンシューマテストによって生成されたコントラクトをホストされている Pact Broker に発行できます。

テスト・スイートのフォルダ構造と命名規則

コンシューマとプロバイダのテストスイートを整理してメンテナーに保つためには、 テストを整理し、コンシューマとプロバイダに一貫した名前をつけることが重要です。そのため、以下の規約を守ることが重要です。

テストスイートのフォルダ構造

テストスイートのフォルダ構造を整理しておくと、レビューやデバッグ、テストの導入の際に、関連するファイルを見つけやすくなります。

コンシューマテスト

コンシューマテストはアプリケーションの異なる Pages に従ってグループ化されます。それぞれのファイルには、ページで見つかるさまざまなタイプのリクエストが含まれています。そのため、コンシューマテストのファイル名はページの参照方法に関するRails標準を使用しています。たとえば、プロジェクトパイプラインページはProject::Pipelines#index ページなので、同等のコンシューマテストはconsumer/specs/project/pipelines/index.spec.js にあります。

テストによって生成されたコントラクトを出力する場所を定義するときは、この例ではcontracts/project/pipelines/ となる同じファイル構造に従います。これはconsumer/resourcesconsumer/fixtures でも同じ構造です。

フォルダの名前も、Railsの命名基準での呼び方に合わせて複数形にする必要があります。

プロバイダのテスト

プロバイダのテストは、コントローラと同じようにグループ化されています。これらのテストには、API エンドポイントに関するさまざまなテストが含まれています。たとえば、あるプロジェクトのパイプラインの一覧を取得する API エンドポイントはprovider/pact_helpers/project/pipelines/get_list_project_pipelines_helper.rb にあります。プロバイダの状態は、コンシューマのテストと同様に、アプリケーションのさまざまなページに応じてグループ化されています。

命名規則

コンシューマテストとプロバイダテストを記述する際、コンシューマとプロバイダに名前が必要な箇所があります。Pact では、これらの名前の付け方について特に制限を設けていないため、デバッグ時にどのコンシューマテストとプロバイダテストが関係しているのかを簡単に把握できるようにするためには、命名規約が重要になります。Pact はまた、コンシューマ名とプロバイダ名を使用して、#{consumer_name}-#{provider_name} 形式でローカルに保存されるコントラクトファイル名を作成します。

コンシューマの命名

フォルダ構造のセクションで述べたように、コンシューマテストはアプリケーション内のさまざまなページに従ってグループ化されます。そのため、コンシューマ名はRails標準の命名形式に従う必要があります。たとえば、Project::Pipelines#index のコンシューマテストはproject フォルダの下にあり、コンシューマ名はPipelines#index となります。

プロバイダの命名

これらはコンシューマーにデータを提供するAPIエンドポイントなので、関連するAPIエンドポイントに従って名前が付けられます。これは HTTP リクエストメソッドで始まり、残りの名前は可能な限り説明的であることに注意してください。たとえば、GET /groups/:id/projects エンドポイントのテストを書く場合、”GET projects endpoint” という名前はつけたくありません。GET /projects エンドポイントもあり、こちらはユーザーが GitLab 全体でアクセスできるプロジェクトの一覧を取得します。

適切な名前を選ぶには、まずAPI ドキュメントをチェックしてそこに書かれているとおりの名前をつけます。つまり、GET /groups/:id/projectsGET list a group's projects と呼び、テストファイル名はget_list_a_groups_projects_helper.rbとします。GET /projectsGET list all projectsと呼び、テストファイル名はget_list_all_projects_helper.rbとします。

テストされるプロバイダが文書化されていない場合もあるので、そのような場合は、HTTP リクエストメソッドの後に、プロバイダが何であるかが簡単にわかるように、できるだけ説明的な名前を付けるようにします。

規約のまとめ

テストフォルダ構造命名規約
消費者テストRailsの参照標準に従います。たとえば、Project::Pipelines#indexconsumer/specs/project/pipelines/index.spec.js Railsの命名基準に従います。たとえば、Project::Pipelines#indexproject フォルダ内のPipelines#index になります。
プロバイダテストRailsのコントローラのようにグループ化されています。たとえば、GET list project pipelines API エンドポイント は次のようになります。provider/pact_helpers/project/pipelines/provider/pact_helpers/project/pipelines/get_list_project_pipelines_helper.rb 文中のAPIドキュメントの命名スキームに従います。たとえば、GET /projects/:id/pipelinesGET list project pipelines となります。