金曜日の午後4時にデプロイが行われました。ユニットテストはグリーンで、コンテナはビルドされ、ロールアウトはエラーなく完了しました。しかし、その後サポートキューが埋まり始めます。チェックアウトが500エラーを返しているのです。バグはテストされたコードの中にはありませんでした。それは2つのサービスが互いにどのように通信していたかにあり、パイプライン内のどのテストもその通信を検証していませんでした。
DevOpsにおけるテスト自動化が埋めるべきギャップとは、まさにこの部分であり、ほとんどのチームが投資を怠っているのはAPIレイヤーです。単体テストは、関数が単独で機能することを証明します。エンドツーエンドのUIテストは、ブラウザがフローをクリックできることを、ゆっくりと不安定な方法で証明します。本番環境で実際に問題を引き起こす、サービス間の契約は、その中間に位置し、しばしばチェックされないままになっています。APIテストはまさにそこに存在します。
ボタン
DevOpsにおけるテスト自動化の真の意味
DevOpsは直線ではなく、ループです。計画、コーディング、ビルド、テスト、リリース、デプロイ、運用、監視、そして再び計画へと戻ります。DevOpsにおけるテスト自動化とは、誰かがリリース前に一度だけ手動で実行するゲートとしてではなく、問題が最も安価に発見できるループのポイントでテストが自動的に実行されることを意味します。

その背後にある原則は「シフトレフト」です。つまり、開発者が変更を記述する時点に近づけて、テストをより早く実施することです。プルリクエストで発見されたバグの修正には数分しかかかりません。本番環境で発見された同じバグは、ロールバック、インシデントチャネル、および事後分析のコストを伴います。自動化は、シフトレフトを可能にするものです。なぜなら、人間はすべてのコミットで回帰テストスイートを手動で再実行することはできませんが、パイプラインはそれができるからです。
「テスト自動化」を一つの大きな塊として扱うのは間違いです。テストピラミッドはそれを複数のレイヤーに分割し、それぞれのレイヤーが異なる問いに答えます。
- 単体テストは、単一の関数が正しい値を返すかどうかを問います。これらは高速で数多く存在します。
- APIテストと結合テストは、サービスが正しい応答を生成し、互いに正しく通信するかどうかを問います。これらは数は少ないですが、それぞれがより広範な領域をカバーします。
- エンドツーエンドテストは、システム全体がユーザーの視点から機能するかどうかを問います。これらは遅く、脆く、数を少なく保つ価値があります。
APIテストは生産的な中間層に位置します。これらは数分ではなく数秒で実行されます。レンダリングされたUIに依存しないため、ボタンが移動しても壊れません。そして、他のサービスや顧客が実際に依存しているインターフェースをテストします。そのため、DevOpsパイプラインでは、APIテストが他のどのレイヤーよりも多くの回帰バグ検出の負荷を担っています。この実践の基礎については、APIテスト自動化が、どこで実行するかを心配する前に、何をアサートすべきか、その理由を説明しています。
DevOpsライフサイクルを段階ごとに見て、APIテストがどこに適合するか
実践的な全体像をここに示します。すべてのチームがすべての段階でAPIテストを必要とするわけではありませんが、選択肢を知ることで、すべてを一つの巨大なデプロイ前ジョブに押し込むのではなく、意図的に選択することができます。
開発中:ローカルおよびプレコミット
変更がCIに到達する前に、開発者はローカルまたは開発環境に対して関連するAPIテストを実行できる必要があります。これは最速のフィードバックループです。ここで不正なレスポンス形式を検出できれば、問題のあるコードがプッシュされることすらありません。
実際には、これは後にCIで実行するのと同じシナリオで、ローカル環境を指しているだけです。一度作成すれば完了です。もし作成したことがない場合は、Apidogでテストシナリオを作成する方法で、リクエストの連鎖や、あるレスポンスから次のレスポンスへ値を取り出す方法を説明しています。
プルリクエスト時:マージゲート
これはAPIテストにとって最も価値のある場所であり、チームが最も見過ごしがちな部分です。プルリクエストが開かれると、パイプラインはサービスを起動し、そのサービスに対してAPIシナリオを実行し、ステータスチェックとして合否を報告します。チェックに失敗するとマージがブロックされます。
これが重要である理由:バグは旅をすればするほど、そのコストは急激に上昇します。PRでのアサーション失敗は、まだ変更が頭の中にある作者にとっては5分で修正できるものです。ステージングで1週間後に発見された同じ失敗は、まるで考古学プロジェクトのようです。PRゲートにAPIテストを配置することは、最も多くの欠陥を左にシフトさせる唯一の変更です。
ビルド後、リリース前:統合および契約チェック
アーティファクトがビルドされ、ステージングまたは統合環境にデプロイされたら、より広範なスイートを実行します。ここでは、実際の連携をテストします。支払いサービスは注文サービスのリクエストボディをまだ受け入れているか、ページネーションはクライアントが読み取るフィールドをまだ返しているか、あるサービスによって発行された認証トークンは別のサービスによって受け入れられるか、といった点です。
この段階は、契約思考が報われる場所でもあります。ローカルでは有効な変更であっても、下流のコンシューマを壊す可能性があります。統合環境に対して完全なシナリオセットを実行することで、単体テストでは構造的に見つけることのできないサービス間の破損を捕捉します。このパターンは、より広範なAPIテスト自動化の実践から引き継がれます。
デプロイ時:スモークテスト
デプロイは、ロールアウトが完了したときに完了するわけではありません。新しいバージョンが実際にトラフィックを正しく処理している証拠があるときに完了します。スモークテストとは、デプロイ直後に重要なパスを検証する小さくて高速なシナリオです。ユーザーは認証できるか、データを読み取れるか、ヘルスチェックに不可欠なエンドポイントは正しい形式で200を返すか、といった点を確認します。
このスイートは小さく、高速に保ってください。その役割はカバレッジではなく、実行可否の信号です。失敗した場合は、自動的にロールバックします。単一の環境フラグを切り替えるだけで、本番環境に対して同じシナリオを実行できます。重複したテストを維持する必要はありません。
本番環境:継続的なモニタリング
デプロイ後もループは止まりません。CIで実行するのと同じAPIシナリオを、合成モニタリングとして本番環境に対して定期的に実行し、顧客が気づく前に劣化したサードパーティの依存関係や期限切れの証明書を検出できます。テストとモニターの境界線は、ほとんどが実行されるスケジュールです。APIモニタリングは、成功したテストを本番環境の早期警告システムに変える方法を説明しています。
これら5つのステージ全体にわたる有用な経験則:本番環境に近づくほど、スイートは小さく、高速になります。PRと統合では広範なカバレッジを、デプロイ時とモニタリングでは薄く、厳格なスモークスイートを使用します。
APIレイヤーがパイプラインでその場所を確保する理由
UIテストにさらに負担をかけるのではなく、APIテストがなぜ主要な位置を占めるに値するのかについて、具体的に述べる価値があります。
これらは高速です。APIシナリオはHTTPと直接通信します。ブラウザを起動したり、DOMを待ったり、遅いレンダリングでヘッドレスChromeが不安定になったりすることはありません。数十のエンドポイントを検証するシナリオは数秒で完了するため、人々が10分かかるジョブを無視することを学習することなく、すべてのコミットで実行できます。
これらは安定しています。UIテストは、クラス名が変更されたり、要素がフレーム遅れで再レンダリングされたりすると壊れます。APIテストは、実際の契約が変更されたときにのみ壊れます。これはまさに知りたいときです。不安定さが少ないということは、人々が赤いビルドを信頼することを意味し、人々が信頼するビルドだけが何かをゲートする唯一のビルドです。
これらは統合されるものをテストします。モバイルアプリ、パートナー統合、独自のマイクロサービスはすべて、CSSではなくAPI契約に依存しています。その契約がサイレントに変更されると、すべてのコンシューマーが一度に壊れます。APIテストはそれを捕捉するレイヤーです。
これが、パイプラインの問題が実際にはAPIの問題である理由です。徹底した単体スイートと優れたUIスイートを持っていても、金曜日の午後のチェックアウトバグを出荷してしまう可能性があります。なぜなら、どちらのレイヤーもサービスが結合する箇所を監視していなかったからです。
Apidog CLIでAPIテストをパイプラインに組み込む
メカニズムは重要です。なぜなら、存在しても自動的に実行されないテストは何も検知しないからです。どのCIシステムでもパターンは同じです。ランナーをインストールし、テストを指し示し、その終了コードがビルドの合否を決定するようにします。
Apidogでは、テストをコードとして書き直す必要はありません。アプリ内で一度シナリオを視覚的に構築すれば、Apidog CLIが同じシナリオをヘッドレスで実行します。CLIはnpmパッケージなので、Node.jsがインストールされているどのCIランナーでも利用できます。
npm install -g apidog-cli
次にシナリオを実行します。ApidogのテストシナリオのCI/CDタブ内でアクセストークンを生成し、シナリオと環境IDを見つけます。そこにはコピーできる完全なコマンドが生成されています。
apidog run \
--access-token $APIDOG_ACCESS_TOKEN \
-t 605067 \
-e 1629989 \
-r cli
ここではいくつかの重要な処理が行われています。-tフラグはIDでシナリオを指定します。フォルダ全体を実行するには-f <folderId>に、厳選されたテストスイートを1つのジョブとして実行するには--test-suite <id>に置き換えてください。-eフラグは環境を選択します。これにより、同じシナリオが重複することなく、ステージング環境に対するPRのゲートとなり、本番環境に対するスモークテストとなります。-rフラグはレポーターを選択します。cliはログに出力し、junitはCIダッシュボードがテストレポートとしてレンダリングできるXMLを出力します。
これをゲートとして機能させているのは終了コードです。すべてのアサーションが成功すると、apidog runは0で終了します。何か失敗すると、非ゼロで終了します。CIシステムはそのコードを読み取り、ステップを失敗とマークし、マージまたはデプロイをブロックします。個別のゲートを設定する必要はありません。終了コードがゲートそのものです。お使いのバージョンで利用可能なすべてのフラグを確認するには、apidog run --helpを実行してください。
以下は、GitHub Actionsに組み込まれたPRゲートの段階です。
name: API Tests
on: [pull_request]
jobs:
api-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Apidog CLI
run: npm install -g apidog-cli
- name: Run API scenarios
env:
APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
run: |
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t 605067 \
-e 1629989 \
-r cli,junit
トークンはリポジトリのシークレットに保存され、ハードコードされることなくenv:を通じてステップに渡されます。このブロックは、GitLab CI、Jenkins、CircleCI、またはAzure Pipelinesでも、それぞれのプラットフォームの構文で囲むだけで使用できます。なぜなら、唯一の実際の依存関係はNodeだからです。プラットフォームごとの詳細な手順は、GitHub ActionsでのAPIテスト自動化とJenkinsとのApidogテスト統合で説明されています。
デプロイ時のスモークテスト段階では、コマンドはほとんど変わりません。本番環境IDを指し示し、シナリオは小さく保ちます。
apidog run --access-token $APIDOG_ACCESS_TOKEN -t 605067 -e $PROD_ENV_ID -r cli
一つのシナリオ、一つの環境切り替え、二つのジョブ。これこそが、テストを一度作成すればライフサイクル全体で実行できる魅力の全てです。
ゲートを静かに無効にするよくある間違い
パイプラインは完全に自動化されているように見えても、何も検知しないことがあります。以下の点に注意してください。
- 終了コードを無視する。誰かがテストコマンドをシェルパイプラインでラップしたり、ビルドが壊れるのを「止める」ために
|| trueを追加したりすることがあります。これは、何も検知するのを止めることにもなります。ビルドは永久にグリーンになります。ランナーの非ゼロ終了を隠蔽してはいけません。その終了こそが全てなのです。 - ハッピーパスのみをテストする。
200 OKを確認して停止するシナリオでは、重要な破損を見逃します。レスポンスボディの形状、フィールドの型、不正な入力に対するエラーレスポンスをアサートしてください。APIアサーションは、ステータスコード以上の検証について説明しています。 - 一つの巨大なデプロイ前ジョブ。すべてのテストをリリース直前の単一のステージに詰め込むことは、シフトレフトの目的を無効にします。破損した契約について、PR上で知るのではなく、出荷の数分前に知ることになります。スイートをステージ全体に広げてください。PRでは広範に、デプロイ時には薄く。
- 共有可能な可変環境に対してテストする。2つのパイプラインが同じデータベースにアクセスすると、一方の実行の書き込みが他方の読み取りを汚染し、信頼を損なう不安定な失敗が発生します。隔離された環境を使用するか、制御できない依存関係の代わりとしてAPIモックを使用して、サードパーティのダウンタイムがビルドを赤くしないようにします。
- 失敗時のレポートを忘れる。テストが成功したときにのみレポートがアップロードされるように設定している場合、必要なときに一度もレポートを見ることができません。アーティファクトのアップロードは、失敗時にも実行されるように設定してください。
よくある質問
DevOpsパイプラインのどこでAPIテストを実行すべきですか?
最低限、プルリクエストにおいてマージゲートとして実行すべきです。それが最も低いコストで最も多くの欠陥を検出できるからです。理想的には、ビルド後に統合環境に対して契約チェックを行い、デプロイ直後に小さなスモークスイートとしても実行します。同じApidogシナリオが各ステージで実行されます。変更するのは環境フラグだけです。PostmanなしでApidogを使用しているチームも同じステージングに従います。
APIテスト自動化とCI/CDの違いは何ですか?
CI/CDは、コードを自動的にビルド、テスト、出荷するパイプラインです。APIテスト自動化は、そのパイプライン内で実行されるテストの一種です。CI/CDはコンベアベルトであり、自動化されたAPIテストはその上の品質ステーションです。CI/CDという用語自体が曖昧な場合は、CI/CDとは何かがその基本を説明しています。
CIで実行するためにAPIテストをコードとして書き直す必要がありますか?
Apidogではその必要はありません。アプリでテストシナリオを視覚的に構築すれば、Apidog CLIが同じシナリオをヘッドレスで実行します。CLIはnpmパッケージなので、Node.jsがインストールされているどのCIランナーでも、1つのコマンドで実行できます。
APIテストはどのようにビルドを失敗させますか?
終了コードを通じてです。シナリオ内のすべてのアサーションが成功すると、ランナーは0で終了します。いずれかのアサーションが失敗すると、非ゼロで終了します。CIシステムはそのコードを読み取り、ステップを失敗とマークし、マージまたはデプロイをブロックします。個別のゲート設定は必要ありません。
パフォーマンステストも同じパイプラインで実行すべきですか?
機能的なAPIテストはすべてのPRで実行し、より負荷の大きいロードテストやパフォーマンス試験は、夜間などの別スケジュールで実行してください。パフォーマンス実行は時間がかかり、安定した環境が必要なため、すべてのコミットにそれらを組み込むと、コミットごとの信号をあまり追加することなくフィードバックを遅らせてしまいます。
最初のAPIテストをどこに配置するか
DevOpsにおけるテスト自動化は、一度構築すれば終わりという一つのゲートではありません。それはループ全体に意図的に配置されたAPIテストです。開発者のマシン上では迅速なフィードバックのために、プルリクエスト上では最も多くの問題を検出するマージゲートとして、ビルド後には契約チェックのために、デプロイ時にはスモーク信号として、そして本番環境ではモニターとして機能します。APIレイヤーは、高速で安定しており、システムが実際に壊れる境界線をテストするため、パイプラインにおいて最も重要な位置を占めます。
もしAPIテストがまだ誰かが手動で実行するクリック可能なステップとして存在しているなら、埋めるべきギャップはマージゲートです。Apidogをダウンロードし、1つのシナリオを構築し、そのCI/CDタブからapidog runコマンドをコピーして、上記のGitHub Actionsブロックを貼り付けてください。その日の午後にはAPIテストが壊れたマージをブロックするようになり、金曜日のデプロイバグはサポートキューではなくプルリクエスト上で赤信号を出すようになるでしょう。
