ほとんどのAPIバグは珍しいものではありません。フィールドの欠落、誤ったステータスコード、負荷時のタイムアウト、契約を確認しないまま出荷された破壊的変更などです。アドホックなテストでも偶然見つかることはありますが、APIテスト戦略はそれらを意図的に検出できる状態にします。
APIテスト戦略とは、何を、どのレイヤーで、デリバリーサイクルのどの段階でテストするかを決める実装計画です。コミットごとに走らせるチェック、毎晩走らせるチェック、リリース前にだけ走らせるチェックを分けることで、最小限のメンテナンスで最大限のカバレッジを狙えます。
APIテスト戦略が実際に意味するもの
テストを書く前に、まず次の4点を決めます。
1. 何をテストするか
ビジネス価値とリスクが高いエンドポイントから優先します。
例:
- チェックアウトAPI
- 決済API
- 認証API
- 顧客データを返すAPI
- 外部システムと連携するAPI
ヘルスチェックのような低リスクエンドポイントより、壊れたときの影響が大きいフローを先にカバーします。
2. どのレイヤーでテストするか
すべてをエンドツーエンドで検証すると、スイートは遅く、壊れやすくなります。
- 単一エンドポイントで検証できるものは単一リクエストテストにする
- サービス間の接続が必要なものは統合テストにする
- ユーザー体験全体が重要なものだけE2Eにする
3. いつ実行するか
高速なチェックはプッシュごとに実行します。遅いチェックは夜間実行やリリース前に回します。
例:
- コミットごと: 機能テスト、契約テスト
- 毎晩: 統合テスト、リグレッションテスト
- リリース前: 負荷テスト、セキュリティテスト
4. 何をパスとみなすか
200 OK だけでは不十分です。少なくとも以下をアサートします。
- ステータスコード
- レスポンススキーマ
- 必須フィールド
- 重要なフィールド値
- エラーメッセージ
- レスポンス時間
例:
GET /api/users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
期待値:
- ステータスが
200 -
idが42 -
emailが有効な形式 - レスポンスが
Userスキーマと一致する
この4点を説明できれば、APIテスト戦略の骨格はできています。
戦略がアドホックテストに勝る理由
アドホックテストは、リクエストを送信し、レスポンスを目視し、問題なさそうなら次に進む方法です。デモや一時的な確認には使えますが、実運用のAPIでは限界があります。
再現性がない
手動チェックは、次の担当者が同じ条件で再実行できるとは限りません。保存された自動テストであれば、常に同じ手順と同じアサーションで実行できます。
ハッピーパスに偏る
手動テストでは、正常に動く入力だけを試しがちです。
実際に障害を起こしやすいのは次のようなケースです。
- 必須フィールドがない
- トークンが期限切れ
- 権限が不足している
- ペイロードが不正
- 一覧が10,000件ある
- 空配列が返る
スケールしない
40個のエンドポイントと5つの環境がある場合、リリースごとに200通りの手動チェックが必要です。現実的ではありません。
テスト戦略では、最初に自動化コストを払う代わりに、その後の変更ごとに同じチェックを自動実行できます。
APIテストピラミッド
テストピラミッドは、どのレイヤーにどれくらいのテストを書くべきかを示す目安です。
/\
/ \ エンドツーエンド / ワークフローテスト(少数、低速、高価値)
/----\
/ \ 統合 / 契約テスト(一部、中速)
/--------\
/ \ 単体 / 単一リクエストテスト(多数、高速、低コスト)
/____________\
最下層: 単一リクエストチェック
1つのエンドポイントにリクエストを送り、レスポンスを検証します。
特徴:
- 高速
- 安価に書ける
- デバッグしやすい
- 失敗箇所が明確
ほとんどのAPIテストはこの層に置きます。
中間層: 統合テストと契約テスト
複数サービスの接続や、プロバイダーとコンシューマー間のインターフェースを検証します。
例:
- 注文APIが在庫サービスと正しく連携する
- 支払いAPIが外部決済プロバイダーと通信できる
- レスポンススキーマがコンシューマーの期待と一致する
最上層: エンドツーエンドワークフロー
複数のエンドポイントをまたぐユーザーフローを検証します。
例:
- 注文を作成する
- 支払いを実行する
- 注文ステータスを確認する
- 通知が送信されたことを確認する
E2Eテストは信頼性が高い一方で、遅く、壊れやすく、維持コストも高くなります。重要なパスに絞って使います。
避けるべきなのは、ピラミッドが逆転することです。大量のE2Eテストと少数の高速テストだけになると、フィードバックが遅くなり、失敗原因の特定も難しくなります。
テストの種類と使い分け
APIテスト戦略では、障害の種類に応じて複数のテストを組み合わせます。
機能テスト
機能テストは、エンドポイントが仕様どおりに動作することを確認します。
主なアサーション:
- ステータスコード
- レスポンススキーマ
- 必須フィールド
- フィールド値
- エラー形式
詳しくは「API機能テスト」を参照してください。
例:
GET /api/users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer <token>
アサーション:
- ステータスが
200 - ボディが
Userスキーマと一致する -
idが42 -
emailが有効なメール文字列
統合テスト
統合テストは、APIが依存先と正しく連携しているかを確認します。
対象例:
- データベース
- 支払いプロバイダー
- 認証サービス
- ダウンストリームAPI
- メッセージキュー
モックでは成功しても、実際の依存関係をつなぐと失敗することがあります。統合テストはそのギャップを埋めます。
詳細は「API統合テスト」で説明されています。
リグレッションテスト
リグレッションテストは、既存の動作が変更によって壊れていないことを確認します。
新しい種類のテストを書くというより、既存の自動化スイートを継続的に再実行する考え方です。
実行タイミング:
- コミットごと
- プルリクエストごと
- リリース前
- 夜間バッチ
詳しくは「リグレッションテスト」を参照してください。
契約テスト
契約テストは、APIプロバイダーとコンシューマーがリクエスト・レスポンス形式に合意していることを検証します。
検出できる破壊的変更:
- フィールド名の変更
- 型の変更
- 必須フィールドの追加
- エンドポイントの削除
- ステータスコードの変更
他チームや顧客が利用するAPIでは、契約テストを必須にするべきです。
詳細は「API契約テスト」を参照してください。
負荷およびパフォーマンステスト
負荷テストは、同時トラフィック下でAPIがどう振る舞うかを測定します。
測定対象:
- p95 / p99 レスポンスタイム
- エラー率
- スループット
- タイムアウト
- 性能劣化が始まるポイント
実行タイミング:
- ローンチ前
- キャンペーンやセール前
- 定期的な性能監視
- 大きなアーキテクチャ変更後
負荷テストは機能テストとは別の領域です。ツールの選択肢は「負荷テストツール」を参照してください。
セキュリティテスト
セキュリティテストは、APIが拒否すべきリクエストを正しく拒否することを確認します。
対象例:
- トークンなし
- 期限切れトークン
- 権限不足
- 他ユーザーのデータ参照
- SQLインジェクション風の入力
- 不正なファイルアップロード
- 過剰なフィールド送信
機密データを扱うエンドポイントでは、少なくとも認証と認可のテストを入れてください。
詳しくは「APIセキュリティテスト」を参照してください。
| テストタイプ | 検出対象 | 実行時期 |
|---|---|---|
| 機能 | 誤ったステータス、スキーマ、値 | コミットごと |
| 統合 | サービス間フローの破損 | コミットごと、または毎晩 |
| リグレッション | 既存動作の破損 | コミットごと、リリース前 |
| 契約 | インターフェースの破壊的変更 | プロバイダー側のコミットごと |
| 負荷 | トラフィック下での遅延や障害 | ローンチ前、定期実行 |
| セキュリティ | 認証、認可、インジェクション、データ漏洩 | リリース前、定期実行 |
ポジティブケース、ネガティブケース、エッジケース
各エンドポイントでは、少なくとも次の3種類の入力をカバーします。
ポジティブケース
有効な入力を送り、成功を期待します。
例:
POST /api/users HTTP/1.1
Content-Type: application/json
{
"name": "Taro Yamada",
"email": "taro@example.com"
}
期待値:
- ステータスが
201 - ユーザーIDが返る
-
emailが送信値と一致する
ネガティブケース
無効な入力を送り、正しい失敗を期待します。
例:
POST /api/orders HTTP/1.1
Content-Type: application/json
{
"customerId": "c_123",
"quantity": -5
}
期待値:
- ステータスが
400 - レスポンスに
quantityの検証エラーが含まれる -
201や500を返さない
ネガティブテストは、APIがクラッシュしたり情報漏洩したりしやすいエラー処理を検証します。
エッジケース
有効な入力の境界を検証します。
例:
- 空配列
- 最大文字列長
0- 負数
- Unicode文字
- タイムゾーン境界
- 夏時間の切り替わり
- 最大ページサイズ
- 存在しないID
実用的なルールとして、ポジティブテスト1つにつき、少なくとも1つのネガティブテストを追加します。
テストデータと環境
テストの信頼性は、データと環境の管理に大きく依存します。
専用のテストデータを使う
本番データに対してテストしないでください。また、特定のレコードが存在する前提にも依存しないようにします。
推奨パターン:
- テスト開始時に必要なデータを作成する
- 既知のフィクスチャをシードする
- テスト終了時に作成データを削除する
- 実行ごとにユニークなIDやメールアドレスを使う
現実的なテストデータを作る方法は「テストデータジェネレーター」を参照してください。
テストを独立させる
各テストは、自分で状態を作り、自分で片付けるべきです。
避けるべき例:
- テストAが作ったユーザーをテストBが使う
- 実行順序に依存する
- グローバル変数に前回のレスポンスを保存する
- 共有DBの固定レコードを前提にする
IDやトークンを次のリクエストに渡す必要がある場合は、同じシナリオ内で明示的に扱います。
環境を分離する
環境ごとにベースURL、トークン、設定値を分けます。
例:
| 環境 | 用途 |
|---|---|
| local | 開発者のローカル確認 |
| ci | プルリクエストやプッシュ時の自動実行 |
| staging | 本番に近い検証 |
| production | 監視や限定的な読み取り確認 |
サンドボックスとテスト環境の違いは「サンドボックスとテスト環境」を参照してください。
変数でパラメータ化する
ホストやシークレットをテストにハードコーディングしないでください。
例:
{{baseUrl}}/api/users/{{userId}}
Authorization: Bearer {{accessToken}}
こうしておけば、同じシナリオをローカル、CI、ステージングで再利用できます。
シフトレフト: より早くテストする
シフトレフトとは、テストを開発サイクルの早い段階に移すことです。
本番で見つかるスキーマ不一致はインシデントになりますが、設計段階で見つかれば数分で修正できます。
1. 先に契約を設計する
実装前に、リクエストとレスポンスのスキーマを定義します。
例:
{
"id": "string",
"email": "string",
"name": "string",
"createdAt": "string"
}
この契約から、テスト、モック、ドキュメントを生成できます。
2. バックエンド完成前にモックでテストする
フロントエンドや連携先チームは、実APIの完成を待つ必要はありません。スキーマから作ったモックサーバーに対して開発とテストを進められます。
3. コミットごとに高速チェックを走らせる
数秒〜数十秒で終わる機能テストや契約テストは、夜間バッチではなく、開発者の通常フローに組み込みます。
詳しくは「API開発におけるシフトレフトテスト」を参照してください。
CIでAPIテストを自動化する
戦略は、自動で実行されて初めて効果を持ちます。
目標は次の状態です。
- プッシュごとにテストスイートを実行する
- 失敗したらマージをブロックする
- レポートを保存する
- 失敗箇所をすぐ確認できる
典型的なCIパイプラインは次の3段階です。
- プッシュごと: 高速な機能テストと契約テストを実行する
- 毎晩またはリリース前: 統合、E2E、負荷、セキュリティテストを実行する
- 常に: JUnit XMLなどの機械可読レポートを出力する
最小限のGitHub Actions例です。
name: api-tests
on: [push]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Run API tests
run: npm test
重要なのはツールではなく、パターンです。
- コードをチェックアウトする
- ランタイムをセットアップする
- APIテストを実行する
- 失敗時は非ゼロ終了コードでビルドを落とす
- レポートを保存する
CI/CDでの詳しい構成は「CI/CDでAPIテストを自動化する方法」を参照してください。
Apidogが戦略にどう適合するか
ここまでの戦略はツール非依存です。設計、テスト、モック、ドキュメントを別々のツールで組み立てることもできます。
ただし、その場合は次のようなドリフトが起きやすくなります。
- 仕様とテストがずれる
- モックと実APIがずれる
- ドキュメントが古くなる
- 契約変更の影響を追いにくい
Apidogでは、API契約、テストシナリオ、モック、ドキュメントを同じ場所で管理できます。同じスキーマを基準にできるため、契約テストやシフトレフトを運用に組み込みやすくなります。
CIでは、Apidog CLIを使って保存済みのシナリオやスイートをヘッドレス実行できます。
インストールします。
npm install -g apidog-cli
保存済みシナリオまたはスイートを実行します。
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioOrSuiteId> \
-e <environmentId> \
-r cli,html,junit
主なオプション:
-
--access-token: 実行認証用のトークン。CIシークレットとして保存する -
-t: 実行するシナリオ、フォルダ、またはスイートのID -
-e: 環境ID。ステージングやCI環境を切り替える -
-r: レポーター。cli、html、json、junitなどを指定する
データ駆動型テストでは、データファイルを渡します。
apidog run \
--access-token "$APIDOG_ACCESS_TOKEN" \
-t <scenarioId> \
-e <environmentId> \
-d ./data/users.csv \
-r cli,junit
レポートをクラウドにアップロードする場合は --upload-report を追加します。特定ブランチに対して実行する場合は --branch を使います。
注意点として、Apidog CLIは保存済みのApidogシナリオやスイートを実行するためのランナーです。負荷ジェネレーターではないため、パフォーマンステストには専用の負荷テストツールを組み合わせてください。
スターター戦略チェックリスト
ゼロからAPIテスト戦略を作る場合は、次の順で進めます。
- [ ] エンドポイントをリスクとトラフィックでランク付けする
- [ ] 上位エンドポイントからポジティブな機能テストを作る
- [ ] エンドポイントごとに少なくとも1つのネガティブテストを追加する
- [ ] リスト、数値、自由テキストを受け取るAPIにエッジケースを追加する
- [ ] 他チームや顧客が利用するAPIに契約テストを追加する
- [ ] 2つ以上のサービスにまたがるフローに統合テストを追加する
- [ ] 環境変数とシークレットを分離する
- [ ] テストデータを生成またはシードする
- [ ] テストを実行順序に依存させない
- [ ] CIでプッシュごとに高速テストを実行する
- [ ] 失敗時にビルドを落とす
- [ ] 遅いテストを夜間またはリリース前にスケジュールする
- [ ] JUnitレポートなどを公開する
- [ ] API変更時にテストスイートもレビューする
- [ ] 削除されたエンドポイントのテストを削除する
最初からすべてを実装する必要はありません。まずは最もリスクの高いエンドポイントに対して、機能テストとネガティブテストを作り、CIで実行できる状態にします。そこから契約、統合、負荷、セキュリティへ広げていくのが現実的です。
FAQ
APIテスト戦略とテスト計画の違いは何ですか?
APIテスト戦略は、どの種類のテストをどのレイヤーでいつ実行するかという高レベルの方針です。
テスト計画は、特定のリリースや機能に対する具体的なドキュメントです。対象エンドポイント、ケース、データ、合格基準などを定義します。
戦略は比較的安定していますが、テスト計画はリリースごとに変わります。
ピラミッドの各レイヤーにはいくつのテストが必要ですか?
固定比率はありません。重要なのは形です。
- 最下層: 多数の高速な単一リクエストテスト
- 中間層: 一部の統合テストと契約テスト
- 最上層: 少数のE2Eワークフロー
遅いE2Eテストが高速な単一リクエストテストより多い場合は、バランスを見直してください。
機能テストがあっても契約テストは必要ですか?
他チームや顧客がAPIを利用しているなら必要です。
機能テストは、エンドポイントが正しく動くことを確認します。契約テストは、インターフェースがコンシューマーを壊す形で変更されていないことを確認します。
API自体は動いていても、フィールド名や型の変更で利用者側が壊れることがあります。
負荷テストはどのくらいの頻度で実行すべきですか?
ローンチ前、既知のトラフィックスパイク前、大きな変更後に実行します。さらに、性能劣化を検出するために週次または月次で定期実行するとよいです。
負荷テストは時間とリソースを使うため、すべてのコミットで実行するべきではありません。CIでは高速テストを維持し、負荷テストは別スケジュールで実行します。
戦略全体をCIで自動化できますか?
再現可能な部分は自動化できます。
CIに組み込みやすいもの:
- 機能テスト
- 統合テスト
- 契約テスト
- リグレッションテスト
別スケジュールにしやすいもの:
- 負荷テスト
- セキュリティテスト
- 長時間のE2Eテスト
Apidog CLIのようなヘッドレスランナーを使うと、保存済みシナリオをCIで実行し、プッシュごとの品質ゲートとして利用できます。
Top comments (0)