ビルドはグリーンです。ユニットテストはパスし、JARはパッケージ化され、アーティファクトはデプロイされました。しかし、最初の本番リクエストがステージングAPIにヒットすると、下流サービスから500エラーが返ってきました。なぜなら、2つ前のコミットで誰かがレスポンスフィールドを変更していたからです。ビルドはすべて問題ないと言いました。しかし実際はそうではありませんでした。APIをチェックしていなかっただけなのです。
これが、ほとんどのBamboo CIパイプラインが抱えるギャップです。Atlassian Bambooは、コードのコンパイル、JUnitスイートの実行、アーティファクトの出荷に優れています。しかし、HTTPエンドポイントがコントラクト通りに動作し続けることを独自に検証する機能はありません。そのセーフティネットが必要な場合は、パイプラインのステージとして自動APIテストを追加する必要があります。このガイドでは、テストの構築にApidogを、Bambooジョブ内でのテスト実行にApidog CLIを使用して、その正確な方法を説明します。
このガイドを終える頃には、プッシュごとにエンドポイントにアクセスし、ステータスコードをチェックし、スキーマに対してレスポンスボディを検証し、コントラクトが破損した瞬間にビルドを失敗させるBambooプランが手に入ります。席ごとのPostmanライセンスは不要で、手書きのアサーションスクリプトを保守する必要もありません。そして、すべてのビルドに実際のHTMLテストレポートが添付されます。Apidogをダウンロードして一緒に試してみる場合は、CLI部分は無料でオープンです。
APIテストがBambooにあるべき理由 — その後ではなく
多くのチームはAPIを手動でテストするか、さらに悪いことに本番環境でテストしています。リリース前に誰かが保存されたリクエストのコレクションをカチカチとクリックし、レスポンスを目視で確認します。それは機能するものの、いつかは機能しなくなります。人は忘れるものです。リリースは金曜日に行われます。誰も再確認しなかったエンドポイントが、まさかの破損を引き起こします。

CIは、その人間的な要素を取り除くために存在します。ビルドサーバーの主な目的は、誰かが実行することを覚えている必要なく、同じチェックが毎回同じ方法で自動的に実行されることです。ユニットテストはすでにそこにあります。統合テストもおそらくそうです。APIテストも同じ扱いを受けるべきであり、いくつかの具体的な理由があります。
- コントラクトはサイレントに破損します。バックエンドの開発者がJSONフィールドの
userIdをuser_idにリネームしました。ユニットテストは関数をテストするため、ワイヤーフォーマットはテストしないため、引き続きパスします。モバイルチームがそれに気づくのは3日後です。レスポンスボディをアサートするAPIテストは、それが導入されたのと同じビルドでそれを検出します。 - 誰も見ていないとステータスコードは嘘をつきます。
201 Createdを返すはずのエンドポイントが、リファクタリング後に200 OKを返すようになりました。機能的には近いですが、技術的には誤りであり、厳密なクライアントはそれを拒否します。パイプラインのアサーションは、これを数秒でフラグします。 - 認証の回帰はコストがかかります。有効な資格情報で
401を返す、誤って設定されたトークンリフレッシュフローは、ログイン画面をダウンさせる種類のバグです。すべてのビルドで認証されたリクエストを実行することは、ユーザーが気づく前にそれを発見することを意味します。 - 環境のズレ。ステージング環境で設定変更が行われたり、機能フラグが反転したり、依存関係がアップグレードされたりします。デプロイごとに同じAPIスイートをステージングに対して実行することで、環境がまだ健全であるかどうかをすぐに知ることができます。
より深い文脈は、チームがそもそもCI/CDを採用するのと同じ理由です。つまり、問題を早期に、修正が安価な段階でキャッチし、修正が高価で恥ずかしい遅い段階ではなく発見することです。APIテストは、ほとんどのパイプラインがスキップするその戦略の単なるレイヤーです。
APIテストがBambooプランにどのように組み込まれるか
ステップバイステップの説明の前に、Bambooのモデルでこれがどこに位置するのかを理解するのに役立ちます。Bambooは作業をプランに整理し、各プランには順序通りに実行される1つ以上のステージが含まれます。各ステージはジョブを保持し、各ジョブは一連のタスクです。タスクは実際のコマンドであり、チェックアウト、コンパイル、スクリプトの実行などです。

APIテストは、ステージ内のジョブ内のタスクになります。自然な配置は、アプリケーションがビルドされテスト環境にデプロイされた後に実行される専用のステージです。これは、リクエストを送信するために稼働中のものが必要だからです。典型的なプランは次のようになります。
Plan: payments-service (プラン: 決済サービス)
├── Stage: Build (ステージ: ビルド)
│ └── Job: Compile & Unit Test (ジョブ: コンパイルとユニットテスト)
│ ├── Task: Source Code Checkout (タスク: ソースコードチェックアウト)
│ └── Task: Maven, clean package (タスク: Maven, クリーンパッケージ)
├── Stage: Deploy to Staging (ステージ: ステージングにデプロイ)
│ └── Job: Deploy (ジョブ: デプロイ)
│ └── Task: Deploy artifact to staging (タスク: アーティファクトをステージングにデプロイ)
└── Stage: API Tests <- this is what you're adding (ステージ: APIテスト <- これが追加するものです)
└── Job: Run API Suite (ジョブ: APIスイートを実行)
├── Task: Source Code Checkout (タスク: ソースコードチェックアウト)
├── Task: Script, install & run Apidog CLI (タスク: スクリプト, Apidog CLIのインストールと実行)
└── Task: Final, publish test report (タスク: 最終, テストレポートの公開)
APIテストステージのタスクがゼロ以外のコードで終了した場合、Bambooはそのステージを失敗としてフラグし、ビルド全体を赤にします。これはまさにあなたが望む動作です。壊れたコントラクトは、見過ごされるのではなく、ラインを停止させるべきです。
そのスクリプトタスクで実際の作業を行うツールはApidog CLIです。これは、Apidogで視覚的に設計したテストシナリオを実行するコマンドラインランナーです。コードを書くことなく、GUIでテストを一度構築すれば、同じテストがターミナルとBambooで変更なしで実行されます。これは、チームが任意のCI/CDシステムでAPIテストを自動化するために使用するのと同じパターンです。Bambooもその多くのターゲットの1つです。
ステップ1:ApidogでAPIテストを構築する
テストがなければCIでテストを実行することはできません。Apidogはテストを設計する場所であり、設計は視覚的であるため、コードを書かないQAエンジニアでもバックエンド開発者と同じスイートを構築できます。

Apidogを開き、テストシナリオを作成します。シナリオとは、上から下へ順序付けられたAPIリクエストのシーケンスであり、各ステップはその前のステップのデータを再利用できます。決済サービスのための現実的なシナリオは次のようになるでしょう。
- 有効な認証情報で
POST /auth/loginを実行し、レスポンスからベアラートークンを抽出する。 - そのトークンを使用して
POST /ordersを実行し、新しい注文を作成し、返されたorderIdを保存する。 GET /orders/{orderId}を実行し、正しいステータスで注文が表示されることを確認する。DELETE /orders/{orderId}を実行してクリーンアップする。
各リクエストにアサーションを追加します。これがリクエストをテストに変える部分です。Apidogでは、スクリプト不要で視覚的にアサートできます。
- ステータスコードが
200(または201、コントラクトが規定する通り)と等しいこと。 - JSONフィールドが存在し、
$.data.statusが"pending"と等しいこと。 - レスポンスがエンドポイントのOpenAPIスキーマに対して検証され、予期しないフィールドタイプや不足している必須プロパティがあればステップが失敗すること。
- レスポンス時間が閾値(例:800ミリ秒)を下回っており、遅い回帰も検出できること。
スキーマベースのアサーションは特筆に値します。Apidogはスキーマファーストであるため、API定義でエンドポイントが約束した形状をすでに知っています。「このレスポンスはスキーマと一致する」とワンクリックでアサートでき、その単一のチェックにより、コントラクトのズレ、フィールド名の変更、型の間違い、プロパティの欠落といった広範なカテゴリの変更を、コードを一切書くことなく防ぐことができます。スクリプト主体のツールから移行してきた場合、これだけでも多くのメンテナンスが不要になります。これは、ApidogがAPIテスト用の一般的なPostmanの代替ツールとなるのと同じ視覚的なアサーションモデルです。
多くのシナリオがある場合は、関連するシナリオをテストスイートにグループ化します。スイートは、一緒に実行できるシナリオの単なるコレクションであり、CIコマンドをシンプルに保つことができます。20個のシナリオをリストする代わりに、ランナーを1つのスイートに指定するだけです。
ローカル、ステージング、本番環境間で変更される可能性のあるもの(ベースURL、資格情報、APIキーなど)には環境変数を使用します。ApidogでbaseUrlをステージングホストに設定したステージング環境を定義します。実行時にCLIにどの環境を使用するかを指示するため、まったく同じシナリオがBambooではステージングに対して、ラップトップではlocalhostに対して実行されます。
ステップ2:Apidogアクセストークンを生成し、IDを取得する
Bambooはビルドエージェント上でヘッドレスで動作します。ブラウザ経由でApidogアカウントにログインできないため、CLIは代わりにアクセストークンで認証します。
テストシナリオ内で、CI/CDタブを開きます。「アクセストークンを追加」をクリックし、「トークンを生成」をクリックします。しばらくの間、値を安全な場所にコピーしてください。スクリプトに貼り付けるのではなく、後でBamboo変数として保存します。このトークンは、ビルドエージェントがプライベートプロジェクトのテストをプルして実行できるようにするものです。
そのCI/CDタブにいる間に、Apidogは完全な実行コマンドを生成してくれます。プロバイダーとして「コマンドライン」を選択すると、テストシナリオIDとプロジェクトIDがすでに埋められた状態で、直接コピーできるものが表示されます。そのコピーされたコマンドがBambooタスクの基礎となります。注意すべき点は次のとおりです。
- アクセストークン: 認証用で、
--access-tokenとして渡されます。 - テストシナリオID: 実行するシナリオを識別する、
-tに続く数値ID。 - 環境ID: CLIにステージングに対して実行するよう指示する、
-eに続く数値ID。
生成されたコマンドは手元に置いておいてください。次のステップでそれをBambooに適応させます。
ステップ3:トークンをBambooプラン変数として保存する
トークンをスクリプトタスクにハードコードしないでください。プランへの読み取りアクセス権を持つ人、およびビルドログを読む人は誰でもそれを見てしまいます。
Bambooで、プランに移動し、「プラン設定」を開き、「変数」タブを見つけます。新しい変数を追加します。APIDOG_ACCESS_TOKENのような明確な名前を付け、その値をトークンとして貼り付けます。Bambooは、名前にpassword、secret、またはtokenを含む変数をマスクするため、適切に命名すれば、値はログとUIに表示されなくなります。
実行時、Bambooはプラン変数を、プレフィックスが付与され大文字化され、ドットがアンダースコアに変換された環境変数としてスクリプトに公開します。APIDOG_ACCESS_TOKENという名前の変数は、シェルタスクで$bamboo_APIDOG_ACCESS_TOKENとして利用できます。ビルドスクリプトでは、生のトークンではなく、常にこれを参照します。
この同じセキュリティ対策は、テストが必要とする他の秘密情報(データベースのパスワード、サードパーティのAPIキー、署名シークレットなど)にも適用されます。それらをマスクされたBamboo変数として定義し、bamboo_環境プレフィックスを通じて読み取ります。
ステップ4:APIテストステージとスクリプトタスクを追加する
次に、それをプランに組み込みます。「プラン設定」で、新しいステージを追加し、「API Tests」という名前を付けます。それにジョブを追加し、次にこの順序でジョブにタスクを追加します。
- タスク1、ソースコードチェックアウト。テストはApidogのクラウドにありますが、リポジトリをチェックアウトすることでエージェントにクリーンな作業ディレクトリが提供され、ローカルデータファイル(例えばCSV反復データ)をコードと一緒にコミットできます。
- タスク2、スクリプト。これが肝心な部分です。スクリプトタスクを選択し、インタプリタをShell(または
/bin/sh)に設定し、インラインスクリプトボディを使用します。このスクリプトはエージェントにApidog CLIをインストールし、シナリオを実行します。
Apidog CLIはnpmパッケージであるため、エージェントにはNode.js v16以降が必要です。エージェントにすでにNodeがある場合、インストール行をスキップできます。ない場合は、Bambooの機能またはDockerベースのエージェントを通じてプロビジョニングしてください。以下に完全なスクリプトボディを示します。
#!/bin/sh
set -e
# Install the Apidog CLI globally on the agent (エージェントにApidog CLIをグローバルにインストール)
npm install -g apidog-cli
# Run the test scenario against staging, output an HTML + CLI report (ステージングに対してテストシナリオを実行し、HTML + CLIレポートを出力)
apidog run \
--access-token "$bamboo_APIDOG_ACCESS_TOKEN" \
-t 637132 \
-e 358171 \
-r cli,html \
--out-dir ./apidog-reports
637132を実際のテストシナリオIDに、358171をステージング環境IDに置き換えてください。これらはステップ2でApidogが生成したコマンドの値です。各フラグの機能に関するいくつかの注意点:
--access-tokenはマスクされたBamboo変数を読み取るため、秘密情報はスクリプトに決して現れません。-t(--test-scenarioの略)は実行するシナリオを選択します。代わりにスイート全体を実行するには--test-suite <id>を、シナリオのフォルダ全体を実行するには-f <folderId>を使用します。-e(--environment)はApidogで定義したステージング環境を選択するため、リクエストは正しいホストと正しい変数に送られます。-r cli,html(--reporters)は、Bambooビルドログに表示されるコンソールレポートと、アーティファクトとして公開できるHTMLレポートの両方を生成します。CLIは、jsonおよびjunit形式もサポートしています。--out-dirはレポートの出力先を制御します。デフォルトは./apidog-reportsです。明示的に設定することで、アーティファクトパスを予測可能にします。
先頭のset -eは重要です。これにより、シェルは最初の失敗したコマンドで終了します。Apidog CLIは、任意のアサーションが失敗した場合にゼロ以外の終了コードを返すように設計されており、このゼロ以外のコードがBambooにビルドの失敗を通知します。これら2つが連携することで、破損したAPIコントラクトがログに埋もれるのではなく、ビルドを赤くすることを保証します。
もし以前にGitHub ActionsにAPIテストを組み込んだことがあるなら、これはなじみ深いでしょう。ランナーとフラグは同じで、YAMLとBamboo UIのラッパーが異なるだけです。
ステップ5:テストレポートをBambooアーティファクトとして公開する
ビルドが赤になった場合、何かが壊れたことを示します。HTMLレポートは、何が壊れたかを教えてくれます。すべてのビルドがレポートを保持するように設定しましょう。
同じジョブで、「アーティファクト」タブに移動し、新しい共有アーティファクトを定義します。
- 名前:
Apidog Test Report - 場所:
apidog-reports - コピーパターン:
**/*
各ビルドの後、Bambooはapidog-reportsディレクトリ内のすべてを収集し、ビルド結果に添付します。任意のビルドを開き、「アーティファクト」タブに移動すると、HTMLレポートをダウンロードまたは表示できます。そこには、リクエストごとの結果、実行されたアサーション、そして失敗したものの正確なレスポンスボディが含まれます。この最後の部分は、実際のデバッグ時間を節約します。失敗したリクエストを手動で再実行する代わりに、ビルドから直接キャプチャされたレスポンスを読み取ることができます。
Bambooでのよりリッチな表示には、junitレポーターも役立ちます。-rリストにjunitを追加し、JUnit XMLファイルを指すJUnit Parserタスクを追加します。そうすると、Bambooはユニットテストの結果を表示するのと同じように、テスト数、パス/フェイルの内訳、失敗傾向をビルドサマリーにネイティブにレンダリングします。
ステップ6:実行して結果を読む
最初の実行は手動でプランをトリガーします。Bambooでプランページから「プランを実行」します。APIテストステージのビルドログを監視します。npmがCLIをインストールし、次にApidogの実行出力がシナリオ名、各リクエスト、各アサーション、および合計を示す最終サマリー行とともに流れていくのがわかります。
結果は2通りです。
すべてのアサーションがパスした場合。CLIは0で終了し、ステージはグリーンになり、ビルドは成功します。HTMLレポートは記録としてアーティファクトとして添付されます。良いことです。次に、それを自動化します。プランをメインブランチへのコミットごとにトリガーするように設定します(プラン設定、トリガー、リポジトリポーリングまたはウェブフック)。これ以降、すべてのプッシュでAPIスイートが人間の介入なしで実行されます。
アサーションが失敗した場合。CLIはゼロ以外のコードで終了し、set -eがスクリプトを停止させ、ステージは赤くなり、ビルドは失敗します。アーティファクトを開き、失敗したリクエストを見つけて、キャプチャされたレスポンスを読み取ります。おそらくフィールドが変更されたか、依存関係がダウンしているためにステージングが502を返したのかもしれません。いずれにせよ、それが導入されたコミットから1〜2分以内にそれを知ることができ、これが全体の成果です。
現実的なコンソールサマリーは次のようになります。
┌──────────────┬──────────┬──────────┐
│ │ executed (実行済み) │ failed (失敗) │
├──────────────┼──────────┼──────────┤
│ iterations (イテレーション) │ 1 │ 0 │
├──────────────┼──────────┼──────────┤
│ requests (リクエスト) │ 4 │ 0 │
├──────────────┼──────────┼──────────┤
│ assertions (アサーション) │ 11 │ 1 │
└──────────────┴──────────┴──────────┘
1 assertion failed: (1件のアサーションが失敗しました:)
GET /orders/{orderId}
expected $.data.status to equal "pending" but got "failed" ($.data.statusが"pending"であるはずが"failed"でした)
この1つの失敗したアサーションこそが、このステージが存在する理由のすべてです。それは、クリーンにコンパイルされ、すべてのユニットテストに合格したにもかかわらず、コントラクトの回帰を捉えました。
CIでスイートを信頼できるものにする
不安定なAPIテストは、テストがないよりも悪いことです。なぜなら、チームに赤いビルドを無視するよう習慣づけてしまうからです。いくつかの習慣がスイートを信頼できるものに保ちます。
- テストデータを隔離します。各実行は、上記の作成・削除の注文フローのように、必要なものを作成し、実行後にクリーンアップする必要があります。先週の火曜日に誰かが作成したレコードに依存するテストは、そのレコードが変更された瞬間に壊れます。専用のステージングまたはテスト環境に対して実行し、決して本番環境に対して実行しないでください。
- 重複なしでカバレッジを得るために、データ駆動型実行を使用します。同じエンドポイントを20種類の入力でテストする必要がある場合、20個のシナリオを作成しないでください。
--iteration-data path/to/data.csv(または-d)を使用する単一のシナリオを使用し、CLIは行ごとに1回実行します。CSVをリポジトリにコミットして、コードと一緒にチェックアウトされるようにします。これは、ローカルで利用するのと同じデータ駆動型テストパターンですが、CIではファイルから駆動されます。 - CLIバージョンを固定します。
npm install -g apidog-cliは最新バージョンを取得します。再現可能なビルドのためには、既知のバージョンnpm install -g apidog-cli@<version>を固定し、CLIの更新が同じコミットの2つのビルド間でサイレントに動作を変更しないようにします。 - 適切なタイムアウトを設定します。
--timeout-request 10000を追加して、エンドポイントがハングした場合に迅速に失敗させ、Bamboo自身のタイムアウトがそれを終了させるまでビルドがハングし続けるのを防ぎます。「リクエストタイムアウト」という明確なエラーは、漠然としたスタックしたビルドよりも優れています。 - APIステージでデプロイをゲートします。APIテストステージは本番デプロイステージよりも前に実行され、失敗したステージはプランを停止するため、破損したコントラクトは本番環境に到達できません。その順序付けがリリースゲートです。これは、単にコンパイルするだけのビルドではなく、真のCI/CDパイプラインを構築するという実用的なバージョンです。
- シナリオを高速かつ集中的に保ちます。20分かかるCIスイートは、すべてのコミットで実行されません。人々はそれを夜間実行に移動させ、迅速なフィードバックを失います。コミットごとのスイートは、クリティカルパス、認証、コアCRUD、支払いフローに限定し、徹底的なエッジケーススイートはスケジュールに基づいて実行します。
まとめ
Bambooはすでに、コンパイルできないコードやパスしないユニットテストからあなたを保護しています。APIテストステージを追加することで、この保護を、サービスが実際にワイヤー経由で公開するコントラクトにまで拡張します。これは、「ローカルでは動いたのに」というほとんどのインシデントが実際に発生するレイヤーです。
設定は簡単です。Apidogで視覚的でスキーマ認識型のテストを構築し、アクセストークンを生成し、それをマスクされたBamboo変数として保存し、シナリオと環境IDを指定してapidog runを実行するスクリプトタスクを追加します。レポートをアーティファクトとして公開し、その背後にデプロイステージをゲートし、コミットごとにプランをトリガーします。その後はすべて自動です。すべてのプッシュでAPIがチェックされ、壊れたコントラクトは、それが障害に変わる前にビルドを赤くします。
Apidogをダウンロードして最初のテストシナリオを構築し、生成されたCLIコマンドをBambooスクリプトタスクにドロップしてください。クリーンにコンパイルされたにもかかわらず回帰を初めて捕捉したとき、そのステージは設定にかかった10分間の価値を証明するでしょう。
