APIテスト自動化のためのCI/CDベストプラクティス12選

現実のパイプラインでも機能する、APIテスト自動化のための12のCI/CDベストプラクティス:ポータブルな実行コマンド、実用的なアサーション、再現性のあるテスト、JUnitレポート、Apidog CLIによるマージゲート。

Ashley Innocent

Ashley Innocent

15 6月 2026

APIテスト自動化のためのCI/CDベストプラクティス12選

Apidog エンタープライズ

オンプレミスデプロイ

SSO & RBAC

SOC 2 準拠

Apidog Enterpriseを見る

壊れたAPIを出荷するグリーンなパイプラインは、パイプラインがないよりも悪い。それは、顧客がチケットを提出するまさにその時まで、チームにすべてが順調だと伝えてしまう。CIにおけるほとんどのAPIテスト設定は、最初は強力に機能するが、静かに腐敗していく。少数のエンドポイントがカバーされ、その後スイートは不安定になり、誰かがノイズを止めるためにcontinue-on-errorを追加し、四半期以内にはテストは実行されるものの、誰も信用しなくなる。パイプラインがグリーンなのは、失敗を無視することを覚えたからだ。

解決策は、より多くのテストではない。それは、現実世界のプレッシャー、例えば金曜日の午後のホットフィックスや3つのサービスにわたるスキーマ変更から来るようなプレッシャーの下でも耐えうるテストを、どのように設計し、実行し、ゲートするかについてのいくつかの決定だ。このガイドでは、それらの決定のうち12個を、GitHub Actions、GitLab CI、または現在使用している任意のランナーにコピーできる具体的な構成とともに解説する。

これらすべてに共通するテーマは同じだ。APIテストはAPIコントラクトの隣に存在し、1つのポータブルなコマンドから実行され、コントラクトが壊れた際には大々的に失敗すべきだ。それが、あなたが仕様を設計し、アサーションを視覚的に記述し、Apidog CLIを通じてCIでスイート全体をヘッドレスで実行できるAPIプラットフォームであるApidogで構築するワークフローだ。アプリケーション内で一度テストを設計すれば、その正確なスイートを任意のパイプラインで単一のコマンドで実行できる。続きを試したい場合は、Apidogをダウンロードして、ご自身のAPIを手元に用意しておいてほしい。

ボタン

CI/CD自体が初めての方のために簡単に説明すると、継続的インテグレーションはすべてのコミットでテストを実行し、継続的デリバリーはテストに合格したビルドをプロモートする。CI/CDとは何か、どのように機能するかで詳細を解説している。この記事の残りの部分は、すでにパイプラインがあり、APIテストがその中で実際に価値を発揮するようにしたいと考えていることを前提としている。

1. APIテストをパイプラインに組み込む。開くのを忘れたタブの中ではなく

最初のベストプラクティスは、人々がスキップしがちなものだ。人間の判断なしに、すべてのプッシュでAPIテストを自動的に実行することだ。リリース前に手動で実行するテストスイートはチェックリストであり、セーフティネットではない。実行することを思い出した頃には、問題を引き起こした変更はすでに6コミットも前になってしまっている。

重要なステージにスイートを組み込む。ほとんどのチームでは、これはプルリクエスト上で行われるため、壊れたAPIはmainに到達するのではなく、マージをブロックする。GitHub Actionsでの最小構成は次のとおりだ。

name: API Tests
on:
  pull_request:
    branches: [main]
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 test suite
        run: |
          apidog run \
            --access-token "$APIDOG_ACCESS_TOKEN" \
            -t "$SCENARIO_ID" \
            -e "$APIDOG_ENV_ID" \
            -r cli,junit \
            --out-dir ./test-results
        env:
          APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}
          SCENARIO_ID: ${{ vars.SCENARIO_ID }}
          APIDOG_ENV_ID: ${{ vars.APIDOG_ENV_ID }}

これが統合のすべてだ。CLIはすべてのアサーションが成功した場合は0を返し、いずれかが失敗した場合は非ゼロのコードを返すため、GitHubは追加の配線なしで実際の失敗時にジョブを赤く表示する。GitHubでの完全なセットアップはGitHub ActionsでAPIテストを自動化する方法で解説している。このパターンはどのランナーにも適用できる。

ベストプラクティス1のポイントは、テストの決定は開発者ではなく機械によって行われるべきだということだ。人間は忘れるが、パイプラインは忘れない。

2. 実行コマンドをCIプロバイダー間でポータブルに保つ

パイプラインは移行する。チームはJenkinsからGitHub Actionsに移行したり、新しいリポジトリのためにGitLabを追加したり、コンプライアンスのためにセルフホスト型ランナーを立ち上げたりする。APIテストが特定のプロバイダーのプラグインエコシステムに固定されている場合、移行のたびにそれらを書き直す必要がある。

それを避ける方法は、どのランナーでも呼び出せる単一のシェルコマンドでテストを呼び出すことだ。Apidog CLIを使えば、スイートを実行するコマンドは誰が呼び出しても同じだ。

apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit

この同じ行は、GitHub Actionsのrunステップ、GitLabのscriptブロック、Jenkinsのシェルステージ、またはTravisのscriptセクションで機能する。変更されるのは、それを囲むラッパーだけだ。例えばGitLabでは次のようになる。

api-tests:
  image: node:20
  script:
    - npm install -g apidog-cli
    - apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SCENARIO_ID" -e "$ENV_ID" -r cli,junit
  artifacts:
    when: always
    reports:
      junit: ./test-results/*.xml

重い処理(リクエストのオーケストレーション、アサーション、環境解決)はCLIにあり、テスト定義はApidogに存在するため、パイプラインのYAMLは薄く保たれる。プロバイダーを切り替える際も、600行ではなく6行をコピーするだけだ。Jenkinsのバリアントについては、そのスタックを使用している場合、CI/CDのためにApidogの自動テストをJenkinsと統合する方法で詳しく説明されている。

3. ステータスコードだけでなく、動作をアサートする

200 OKだけをチェックするテストは、APIが空の配列、間違った通貨、クライアントがオブジェクトを期待する場所でnullを返している場合でも通過してしまう。ステータスコードのみのテストは、グリーンなパイプラインが壊れたレスポンスを出荷する最大の理由だ。

実際のアサーションは、レスポンスの形状と内容、つまり存在するフィールド、その型、コンシューマにとって重要な値をチェックする。Apidogでは、これらのアサーションをレスポンスに対して視覚的に構築するため、頭の中でJSONPathを推測するのではなく、実際のリクエスト内容に対してアサートできる。堅牢な注文検索テストは、ステータスが200であること、order.totalが数値であること、currencyが送信した値と等しいこと、items配列が空でないことをアサートする。これらそれぞれが独立して失敗する別のアサーションであるため、ビルドが赤くなれば、どのコントラクトが壊れたかを教えてくれる。

3つのルールにより、アサーションは長期的に維持される。

リファクタリングに耐えうるアサーションの記述について深く知りたい場合は、APIアサーションに関するガイドを参照してほしい。強力なアサーションが、スモークテストをコントラクトテストに変え、コントラクトテストが重要なリグレッションを捕捉する。

4. 環境とシークレットをハードコード値ではなく、設定として管理する

テストはさまざまなターゲットに対して実行される。ローカルスタック、ステージングAPI、本番スモークエンドポイントなどだ。ベースURL、認証トークン、テナントIDはそれぞれで変わる。これらの一部でもテストにハードコードすると、ステージングテストが誤って本番環境を叩いたり、トークンがGitの履歴に残ったりする原因となる。

環境を名前付き設定として保持し、差異を注入する。Apidogでは、環境は1つのターゲットのベースURLと変数を保持し、CI実行時に-eフラグでどれを使用するかを選択する。パイプラインはシークレットストアからアクセストークンを供給し、リポジトリ内のファイルから供給することはない。

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t "$SCENARIO_ID" \
  -e "$STAGING_ENV_ID" \
  -r cli,junit

同じシナリオを異なる-e値に指定するだけで、本番環境のスモークテストになる。テスト自体は何も変わらず、解決対象となる環境だけが変わる。APIDOG_ACCESS_TOKENはGitHub Secrets、GitLab CI/CD変数、またはランナーの資格情報マネージャーに保存し、名前で参照する。ルールはシンプルだ。環境間で異なるもの、またはシークレットなものはすべて設定であり、設定は実行時に注入される。

5. テストを決定論的にして、パイプラインを信頼できるものにする

フレーキーテストとは、コードとは関係のない理由で失敗するテストのことだ。それはパイプラインの信頼性を破壊する最も速い方法でもある。スイートが「時々失敗する」ようになると、開発者はグリーンになるまでジョブを再実行し始め、結果として本当の失敗が偽の失敗のノイズの中に隠れてしまう。

ほとんどのAPIテストの不安定さには、いくつかの予測可能な原因がある。

決定論的であることは、人々が尊重するパイプラインと、人々が回避するパイプラインの違いだ。早期にエンジニアリングに投資するべきだ。フレーキーテストは雪だるま式に増えていく。

6. APIテストステージを高速に保つ。そうしないと開発者が回避するようになる

すべてのプルリクエストで20分かかるテストスイートは、開発者が嫌悪し、最終的には無効にする負担となる。CIにおいて速度は「あると嬉しい」ものではなく、スイートがそもそも実行され続けるために不可欠なものだ。ほとんどのチームが目指すのは、PRにおけるAPIステージが5分未満であることだ。

そこに到達するためのいくつかのレバーがある。

GitHub Actionsでの段階的なパターンを次に示す。PRではクイックスモーク実行、スケジュールではフルスイートを実行する。

on:
  pull_request:
    branches: [main]
  schedule:
    - cron: '0 2 * * *'   # nightly full regression

jobs:
  api-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install -g apidog-cli
      - name: Run suite
        run: |
          if [ "${{ github.event_name }}" = "pull_request" ]; then
            apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$SMOKE_ID" -e "$ENV_ID" -r cli,junit --out-dir ./test-results
          else
            apidog run --access-token "$APIDOG_ACCESS_TOKEN" -t "$FULL_ID" -e "$ENV_ID" -r cli,junit --on-error continue --out-dir ./test-results
          fi
        env:
          APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}

実行される高速なステージは、無効にされる徹底的なステージよりも価値がある。

7. コンソールテキストの壁ではなく、機械で読み取り可能な結果を公開する

ビルドが失敗した場合、「APIテストが失敗しました」だけでは不十分だ。どのアサーションが、どのシナリオで、どのリクエストで失敗したかを知る必要がある。数千行のコンソール出力がある赤いビルドは、テストがないのとほとんど変わらない。誰かがそれを読む必要があるからだ。

解決策は、CIサーバーがネイティブに解析できる形式で結果を出力することだ。JUnit XMLは標準的なCIテスト結果形式であり、ほとんどすべてのプラットフォームがそれを読み取る。Apidog CLIはjunitレポーターを使用してそれを作成する。

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t "$SCENARIO_ID" \
  -e "$ENV_ID" \
  -r cli,html,junit \
  --out-dir ./test-results

このコマンドは、同じ実行結果を3つのビューで出力する。ライブコンソール出力用のcli、人間が開いて閲覧できるレポート用のhtml、そして機械用のjunitだ。パイプラインをXMLに指定すると、プラットフォームはそれを構造化されたテストごとの結果に変換する。

      - name: Publish test report
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: api-test-results
          path: ./test-results

if: always()に注目してほしい。実行が失敗した場合でもレポートが公開されることを望むだろう。なぜなら、失敗した実行結果はまさにそれが必要な時だからだ。その効果は絶大だ。「APIビルドが壊れた」ではなく、「チェックアウトシナリオのcart-totalアサーションが失敗し始めた」という情報が得られ、デバッグセッションが一瞥で済むようになる。

8. ブランチ保護機能でスイートをマージのゲートにする

何もブロックしない合格するテストスイートは、単なる通知に過ぎない。CIの目的は、壊れたコードをマージ不可能にすることであり、そのためにはほとんどのチームが設定しているよりももう一歩進んだ「ブランチ保護」が必要だ。

終了コードがローカルでの作業を担う。Apidog CLIはどのアサーションが失敗しても非ゼロで終了するため、実際の失敗時にはジョブが赤くなる。しかし、PR上の赤いジョブは、そのチェックを必須にするまでは単なる助言に過ぎない。GitHubでは、APIテストのチェックをmainブランチの必須ステータスチェックとして設定する。これにより、グリーンになるまでマージボタンは無効のままだ。GitLabとBitbucketにも、マージリクエスト設定に同様の機能がある。

これが、リグレッションを捕捉するスイートと、後からリグレッションを記録するスイートの違いだ。必須チェックがない場合、締め切りに追われた開発者はマージをクリックし、壊れたAPIがその横に赤いチェックマークがついたまま出荷されてしまう。ゲートがあれば、プラットフォームはそれを拒否する。テストは単なる提案ではなくなり、ツールが強制するルールとなる。

これをベストプラクティス7の機械で読み取り可能な結果とコミットステータスの統合と組み合わせれば、GitホストはPR上で正確な失敗チェックをインラインで表示する。フィードバックループが完結する。プッシュ、テスト、ブロック、修正、グリーン、マージ。

9. API仕様からテストカバレッジを生成する。手動で記述するのではなく

APIテストで最も時間がかかるのは、テストをAPIと同期させ続けることだ。新しいエンドポイントごとに新しいテストが必要であり、変更されたフィールドごとにアサーションの更新が必要だ。手動で行うと、テストは常にAPIに遅れをとり、そのギャップがリグレッションが発生する場所となる。

効果的な方法は、契約からテストを駆動することだ。APIにOpenAPI仕様がある場合、そこからテストの足場を生成できる。つまり、エンドポイントごとに1つのリクエストが生成され、スキーマがすでに期待されるレスポンスの形状を記述している。Apidogでは、仕様とテストが同じワークスペースに存在するため、テストシナリオは文書化されたエンドポイントから直接構築でき、書き写す必要はない。生成フローについては、OpenAPI仕様からAPIテストコレクションを生成する方法で解説している。

これはCIにおいて重要だ。なぜなら、仕様駆動テストは特定の一般的なバグ、つまりドキュメントが約束するものとAPIが返すものとの間のずれを捕捉するからだ。テストが仕様から生成され、稼働中のAPIに対して実行されると、不一致があればビルドは失敗する。契約は実行可能になる。ビジネスロジックをエンコードするアサーションは手動で記述するが、「このエンドポイントは存在し、文書化された形状を返すか」という定型的な部分は手動で記述する必要はない。その重荷は仕様に任せよう。

10. データ駆動型テストを使用して、シナリオを重複させることなくエッジケースをカバーする

同じエンドポイントでも、入力によって動作が異なる場合がある。例えば、有効な注文、信用限度額を超える注文、不明なSKUを含む注文、サポートされていない通貨での注文などだ。それぞれに別のシナリオを記述すると、誰も保守しない数百ものほぼ同じテストにスイートが膨れ上がってしまう。

データ駆動型テストは、1つのシナリオを多数の入力行に対して実行する。リクエストとアサーションを一度定義し、その後ケースのテーブルを供給する。Apidog CLIは-dフラグでデータファイルを受け取る。

apidog run \
  --access-token "$APIDOG_ACCESS_TOKEN" \
  -t "$SCENARIO_ID" \
  -e "$ENV_ID" \
  -d ./test-data/orders.csv \
  -r cli,junit \
  --out-dir ./test-results

orders.csvの各行は、それぞれ合否を持つ1つのイテレーションとなる。1つのシナリオ、1つのCLI呼び出しで、完全なエッジケースカバレッジを実現し、どの入力行が失敗したかを示すJUnitレポートが生成される。これにより、スイートを小さく保ちながらカバレッジを広げることができ、CIで望ましいトレードオフだ。CSVまたはJSONを使用したデータ駆動型APIテストに関するガイドでは、データファイルの構造化について詳しく解説している。

このパターンは、単一のエンドポイントが最も多くの分岐を持ち、静かにリグレッションを引き起こす可能性が最も高い、バリデーションロジックや価格設定ルールにおいて最大の効果を発揮する。

11. 実際の環境に対してデプロイ後のスモークテストを実行する

ステージング環境に対してパスするテストは、ビルドが良好であることを教えてくれる。デプロイが機能したかどうかは教えてくれない。設定のずれ、環境変数の不足、誤ったルーティングのロードバランサー、有効期限切れの証明書など、これらすべてはすべてのマージ前テストを通過し、実際にデプロイされた環境でのみ問題を引き起こす。

その防衛策は、デプロイ後にライブターゲットに対して実行されるスモークテストだ。これは、本番環境や新しくデプロイされた環境に向けられた、重要パス、認証フロー、最も重要な読み取りおよび書き込みエンドポイントのみをカバーする、小さく高速なスイートだ。実行コマンドはポータブルであり(ベストプラクティス2)、環境は単なる設定であるため(ベストプラクティス4)、これは異なる-e値を持つ同じスイートになる。

  smoke-after-deploy:
    needs: deploy
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm install -g apidog-cli
      - name: Smoke test production
        run: |
          apidog run \
            --access-token "$APIDOG_ACCESS_TOKEN" \
            -t "$SMOKE_SCENARIO_ID" \
            -e "$PROD_ENV_ID" \
            -r cli,junit \
            --out-dir ./smoke-results
        env:
          APIDOG_ACCESS_TOKEN: ${{ secrets.APIDOG_ACCESS_TOKEN }}

スモークテストが失敗したら、ユーザーが気づく前にロールバックする合図だ。ブルー/グリーンデプロイやカナリアデプロイを実行しているチームは、トラフィックを切り替える前に新しいバージョンに対してスモークスイートを実行する。これにより、最初の実際のユーザーが壊れたデプロイを見つけることがなくなる。コストはパイプラインのわずか1分間だ。代わりに、サポートチケットから問題を発見する。

12. テストスイートは「完成させるセットアップ」ではなく、「保守するコード」として扱う

最後のベストプラクティスは考え方だ。CIテストスイートは完了するプロジェクトではなく、保護するAPIとともに保守する資産だ。パイプラインが信頼され続けるチームは、不安定なテストをバグとして、遅いステージを技術的負債として、カバレッジのギャップを発生しうるリグレッションとして扱うチームだ。

長期的にスイートを健全に保つためのいくつかの習慣がある。

テスト定義はApidogにあり、パイプラインは薄い呼び出ししか持たないため、ほとんどのメンテナンスは簡単な場所で行われる。つまり、アプリケーション内でシナリオとアサーションを追加し、CI設定はほとんど変更されない。これを正しく行うチームは、YAMLの管理に時間を費やすのではなく、カバレッジの向上に時間を費やす。大規模なスイートの編成に関するより広範な視点については、Apidogテストスイート:APIテストを自動化するよりスマートな方法を参照してほしい。

まとめ

これら12のプラクティスは互いに補強し合う。ポータブルな実行コマンドは、デプロイ後のスモークテストを些細なものにする。決定論的なテストは並列処理を安全にし、ステージを高速に保ち、開発者がそれを使い続けるようにする。機械で読み取り可能な結果はブランチ保護を意味あるものにする。なぜなら、ゲートがテキストの壁ではなく、特定の失敗したチェックを指し示すからだ。仕様駆動型およびデータ駆動型テストは、保守が遅くなることなくスイートを包括的に保つ。

共通の基盤は、テストを契約の近くに置き、1つのコマンドから実行可能にすることだ。それが一言で言うApidogのワークフローだ。APIとそのテストを1箇所で設計し、その後その正確なスイートを任意のパイプラインでapidog runで実行する。CLIは失敗時に非ゼロで終了し、CIが解析するためのJUnitを出力し、GitHub Actions、GitLab、Jenkins、またはセルフホスト型ランナーが呼び出しても同じように動作する。

小さく始める。実際のasserionと必須ステータスチェックを組み合わせて、1つの重要なシナリオをPRパイプラインに組み込む。そのループを信頼できるものにし、その後、段階的な実行、データ駆動型のエッジケース、デプロイ後のスモークテストといった残りの要素を重ねていく。信頼できるパイプラインとは、本当に何か壊れた場合にのみ赤くなり、本当に安全に出荷できる場合にのみグリーンになるものだ。Apidogをダウンロードして、今日から最初のシナリオを構築しよう。

ボタン

FAQ

CIとCI/CDにおけるAPIテストの違いは何ですか?CI(継続的インテグレーション)は、すべてのコミットまたはプルリクエストでAPIテストを自動的に実行し、早期にリグレッションを捕捉します。CD(継続的デリバリー)は、それらのチェックを通過したビルドをデプロイターゲットにプロモートします。APIテストは両方に存在します。マージ前のスイートは統合をゲートし、デプロイ後のスモークスイートはデリバリーを検証します。同じApidog CLIコマンドが両方のステージで機能します。

パイプラインでAPIテストを実行するためにコードを書く必要がありますか?いいえ。Apidogでリクエストとアサーションを視覚的に構築し、その後apidog runコマンド1つでヘッドレスで実行します。パイプラインにはそのコマンド1つだけでよく、これによりCI構成を薄く保ち、QAエンジニアがコードベースのフレームワークを保守することなくテストを所有できるようになります。完全な手順はCI/CDでAPIテストを自動化する方法で解説しています。

CIでAPIテストが不安定になるのを防ぐにはどうすればよいですか?最大の3つの原因は、共有される可変テストデータ、非同期操作に関するタイミングの仮定、および制御できないサードパーティの依存関係です。各テストに独自のデータを与え、固定時間待つのではなく非同期条件をポーリングし、制御できない外部境界をモック化します。どの順序で、どの実行でもパスするスイートが目標です。

失敗したAPIテストでマージをブロックするにはどうすればよいですか?2つの要素があります。まず、テストランナーは失敗時に非ゼロで終了する必要があります。Apidog CLIはどのアサーションが失敗してもこれを行うため、ジョブは自動的に赤くなります。次に、そのジョブをGitホストのブランチ保護ルールで必須ステータスチェックとしてマークします。チェックがパスするまでマージボタンは無効のままです。

GitHub Actions、GitLab、Jenkinsで同じAPIテストを実行できますか?はい。テストロジックはApidogにあり、パイプラインはapidog runを呼び出すだけなので、コマンドはプロバイダー間で同一です。変更されるのは周囲のYAMLまたはパイプラインスクリプトだけです。そのポータビリティこそが、CIプロバイダーの移行を書き直しではなく6行の編集で済ませる理由です。GitHubに特化したセットアップについては、GitHub ActionsでAPIテストを自動化する方法を参照してください。

APIテストステージはどのくらい速くあるべきですか?プルリクエストでは5分未満を目指しましょう。PRで高速なスモークスイートを実行し、夜間に完全なリグレッションスイートを実行すること、独立したシナリオを並列化すること、CLIのインストールをキャッシュすることで実現できます。遅いステージは、最終的に開発者が無効にするステージであり、その目的を無にするものです。

ApidogでAPIデザイン中心のアプローチを取る

APIの開発と利用をよりシンプルなことにする方法を発見できる