緑色のステータスコードは嘘をつきます。`POST /orders` エンドポイントが `201 Created` を返し、レスポンスボディも完璧で、テストがパスしたとします。しかし、実際に行は正しいステータスでデータベースに保存されたでしょうか?在庫数は減りましたか?HTTPレスポンスのみを読み取るテストは、APIが「言った」ことだけを確認し、システムが「行った」ことは確認しません。このギャップを埋めるには、データベース自体を調べる必要があります。
テストシナリオ内のデータベースクエリが真価を発揮するのは、まさにここです。リクエストの前に既知の状態をシードし、リクエストを実行し、その後テーブルをクエリしてディスク上の真実を確認します。Apidog には、データベース接続とデータベース操作プロセッサを通じてこれが組み込まれているため、外部スクリプトなしで、HTTP呼び出しを駆動するのと同じシナリオ内でSQLまたはNoSQLコマンドをステップとして実行できます。シナリオの構築に慣れていない場合は、Apidogでテストシナリオを作成する方法に関するガイドが、この記事の基礎となるリクエストレベルの基本をカバーしています。リレーショナルストアがこのデータをどのようにモデル化しているかについて復習するには、MDNのサーバーサイド概要が優れた入門書です。
ボタン
テストにおけるデータベース操作の利点
データベースに一切触れないAPIテストはブラックボックスです。レスポンスを信頼します。ほとんどの場合、それで問題ありませんが、興味深いバグはAPIが返すものとそれが永続化するものとの間のギャップに存在します。例えば、決して反転しないステータスフィールド、どこにもポイントしない外部キー、ソフトデリートがハードデリートになってしまう、などです。
データベースステップにより、純粋なHTTPテストではできない3つのことが可能になります。
- シード:テストが残存データに左右されないよう、正確な開始状態を用意します。
- 真実との照合:APIが書き込んだと主張する行を読み取り、真実と照合します。
- 実際の値を抽出:データベースから実際の値を抽出し、次のリクエストに渡します。これにより、テストは推測ではなく、サーバーが実際に生成したIDを使用します。
Apidogはこの機能を2つに分けています。まず、「設定 > データベース接続」の下で再利用可能な接続を作成します。次に、データベース操作ステップをリクエストにプリプロセッサー(リクエストの前に実行)またはポストプロセッサー(リクエストの後に実行)としてアタッチします。1つの接続をプロジェクト内のすべてのシナリオで再利用できます。
計画を立てる前に、対象範囲について注意点があります。MySQL、SQL Server(2014以降)、PostgreSQL、Oracleは無料プランで利用できます。ClickHouse、MongoDB、Redisは有料です。MongoDBのドキュメントには明記されていますが、MongoDBへの接続は有料機能です。Redisも同様です。したがって、以下のMySQLの解説は無料プランで実行できますが、MongoとRedisのセクションは有料プランが必要です。
ステップ1: データベース接続を作成する
「設定 > データベース接続」を開き、右上にある + 新規 をクリックします。データベースの種類を選択し、接続フィールドに入力します。
- ホスト(例:
db.staging.internalまたは127.0.0.1) - ポート(MySQLの場合は
3306) - ユーザー名とパスワード
- データベース名(例:
shop)

データベースが踏み台サーバーの背後にある場合は、SSHトンネルセクションを展開し、ジャンプホストの詳細を追加します。MySQLは4つのオプションを持つSSLモードも公開しています: Prefer(デフォルトで、SSLを試行し、失敗した場合はフォールバック)、Require、Verify CA、Verify Full。サーバーがサポートする最も厳格なものを選択してください。その後、保存をクリックします。
接続に関する2つの注意点が、混乱した午後を救ってくれます。
- MySQL 8認証。デフォルトの`caching_sha2_password`プラグインが接続を拒否する場合があります。認証エラーが発生した場合は、`ALTER USER 'tester'@'%' IDENTIFIED WITH mysql_native_password BY '...';` を使用してユーザーを切り替え、再試行してください。MySQLリファレンスマニュアルには、プラグインの違いが詳細に説明されています。
- 認証情報はローカルです。接続の詳細はご自身のマシンに保存され、クラウドには同期されません。各チームメンバーがそれぞれ接続を設定します。チームで調整している場合は、データベース接続設定の共有に関するメモでワークフローが説明されています。
ステップ2: プリプロセッサーでデータをシードする
注文作成フローをテストしているとします。注文を行う前に既知の顧客が存在するようにしたいので、テストがテーブルに存在する可能性のあるデータに依存しないようにします。
リクエストを開き、プリプロセッサーを見つけ、データベースプロセッサーを追加にマウスを合わせ、データベース操作を選択します。`seed customer` のような名前を付け、MySQL接続を選択し、SQLコマンドを入力の下に挿入文を記述します。動的変数は {{variable_name}} 構文を使用するため、環境から直接値を引っ張ることができます。
INSERT INTO customers (id, email, status)
VALUES ({{customer_id}}, '{{customer_email}}', 'active')
ON DUPLICATE KEY UPDATE status = 'active';
これで、リクエストは保証された状態に対して実行されます。顧客は存在し、アクティブで、後のステップで既に知っているIDを持っています。プリプロセッサーでのシードは、テストの実行順序による副作用に依存するのではなく、各テストを自己完結型に保ちます。
ステップ3: ポストプロセッサーでデータベースに対してアサートする
これが核心です。リクエストで注文が作成されます。それが返された後、`orders` テーブルをクエリして、正しいステータスで行が存在することを確認します。
APIを呼び出すリクエストを追加します。
POST /api/orders
Content-Type: application/json
{
"customer_id": {{customer_id}},
"items": [{ "sku": "APRON-01", "qty": 2 }]
}
レスポンスボディに新しい注文IDが含まれていると仮定し、通常のレスポンスアサーションでそれを `order_id` という変数にキャプチャします。次に、そのリクエストのポストプロセッサーを開きます。DESIGNモードでは実行タブに、DEBUGモードではリクエストタブにあります。ポストプロセッサーを追加にマウスを合わせ、データベース操作を選択し、`verify order row` と名前を付け、接続を選択します。
操作を設定の下で、操作を選択し、SQLを入力します。
SELECT id, status, total_cents
FROM orders
WHERE id = {{order_id}};
クエリ結果はオブジェクトの配列として返され、1行につき1つのオブジェクトです。単一のフィールドを抽出するには、結果を抽出 (オプション) を開き、結果を変数に抽出エントリを追加します。`db_order_status` のような変数名を設定し、最初の行からフィールドを分離するJSONPath式を設定します。
$[0].status
送信をクリックし、コンソールで生の結果と抽出された値を確認します。これで `db_order_status` にはディスク上の実際の値が保持されます。それが `pending`(またはAPIが設定することになっている値)と等しいというアサーションを追加すると、テストはHTTPエコーだけでなく、最終的に永続性を検証します。APIが `201` を返したが `status = 'draft'` と書き込んだ場合、このステップがそれを検出します。
ステップ4: データベース値を抽出し、ダウンストリームで使用する
抽出はアサーションのためだけではありません。多くの場合、データベースはレスポンスが返さない値を保持しており、次のリクエストでそれが必要になります。
注文の作成と同時に、サーバー上で内部的な `fulfillment_ref` が生成され、行に書き込まれるものの、APIレスポンスからは省略されるフローを想像してください。次のリクエストである `GET /api/fulfillments/{ref}` はそれを必要とします。ポストプロセッサーでそれをクエリします。
SELECT fulfillment_ref
FROM orders
WHERE id = {{order_id}};
変数名 `fulfillment_ref` と JSONPath式 `$[0].fulfillment_ref` を使用して抽出します。Apidogはその変数を環境にスコープするため、次のリクエストではそのパスまたはボディで `{{fulfillment_ref}}` を参照するだけで、実際のサーバー生成値を取得します。これはHTTPレスポンスを連鎖させるのと同じパターンで、テストステップ間でデータを渡す および APIテストのオーケストレーションとデータ受け渡し で説明されているものと同じですが、真実の源がJSONボディではなくテーブルである点が異なります。
MongoDBとRedis: NoSQLのバリアント
プロセッサーはNoSQLストアに対しても同じように機能しますが、設定インターフェースが異なります。どちらも有料機能なので、それに応じて計画してください。必要であれば、Apidogドキュメントに完全なフィールドリファレンスがあります。
MongoDB
データベース操作ステップを追加し、タイプとしてMongoDBを選択します。生のSQLではなく、Find、Insert、Update、Delete、およびデータベースコマンドの実行を含む操作タイプのドロップダウンが表示されます。CRUDアクションの場合は、コレクション名が必須です。クエリ条件フィールドはJSONを受け取ります。
{ "_id": "65486728456e79993a150f1c" }
Apidogは一致するID文字列を自動的にObjectIdに変換するため、自分でラップする必要はありません。BSONタイプが必要な場合は、ヘルパー `ISODate(...)`、`ObjectId(...)`、`NumberDecimal(...)`、`NumberLong(...)` がサポートされています。MongoDBマニュアルには、これらがそれぞれ格納された値にどのようにマッピングされるかが記載されています。接続は、完全な接続文字列または個別のホストおよび資格情報コンポーネントのいずれかを受け入れます。
補足として:MySQLのフローではJSONPathを介した変数への抽出が記載されていますが、MongoDBおよびRedisのドキュメントでは同じ結果を変数に抽出メカニズムは説明されていません。したがって、MongoDB操作は状態のシードと確認に重点を置き、コンソールで検証するまではSQLスタイルの抽出パスが同一に機能すると仮定しないでください。
Redis
Redis接続では、ホスト、ポート、パスワード、データベースインデックスが要求されます。視覚的な操作では、GET、SET、DELETEをサポートする操作タイプのドロップダウンを使用します。キャッシュされたセッションを読み取るには、GETを選択し、キーを `user:session:123` のように設定します。ドロップダウンでカバーされていないものについては、Redisコマンドの実行タブで有効なコマンドを実行できます。
KEYS user:*
これにより、APIが書き込むべきキャッシュエントリを確認したり、エンドポイントがそれを再投入することを証明するためにテストの前にクリアしたりすることができます。
高度なバリエーションと制限事項
大規模なスイートを構築する前に知っておくべきいくつかの事項:
- ループ。 ForEachステップで行を反復処理する場合、現在のループ項目を
{{$.StepID.element.field}}で参照します。ここでStepIDはループステップの実際の番号です。反復ごとに1行をアサートするのに便利です。 - DB値に基づく分岐。 ステータスフィールドを抽出し、その値に基づいてシナリオの残りをルーティングします。APIテストシナリオにおける条件ロジックとデータベース読み取りを組み合わせることで、行が
paidの場合はあるパスを、pendingの場合は別のパスをテストで実行できます。 - 環境ルーティング。 詳細はこの後に説明しますが、要するに:環境ごとに1つの接続を定義すると、Apidogが自動的に適切な接続を選択します。
- ストアドプロシージャ。 ビジュアルインターフェースはストアドプロシージャのような複雑な操作を処理しません。ステップ内のSQLは単純なステートメントに留めてください。
- Oracleのセットアップ。 Oracleは接続する前に、マシンに個別のOracle Clientがインストールされている必要があります。
環境ごとの認証情報の管理
テストが誤って本番データにアクセスするような事態は避けたいものです。Apidogの解決策は、環境ごとに1つのデータベース接続を用意することです。`staging` 接続と `local` 接続をそれぞれ作成し、それぞれに独自のホストとパスワードを設定します。
次に、右上隅のドロップダウンを使用して環境を切り替えます。Apidogは、シナリオ内のすべてのクエリを現在選択されている環境に一致する接続に自動的にルーティングします。`staging` を選択すると、`SELECT` はステージング環境で実行され、`local` に切り替えると、まったく同じステップがラップトップのデータベースに対して実行されます。SQLやステップを変更する必要はありません。実行中に手動で再設定することなく、環境ごとに認証情報が異なります。
これらの認証情報はローカルに存在し、同期されないため、本番環境のパスワードが共有クラウドプロジェクトに漏れることもありません。各エンジニアが自身の認証情報を管理します。
Apidog CLIでワークフローを自動化する
アプリでシナリオがパスしたら、CIでヘッドレス実行し、すべてのプルリクエストがHTTP契約だけでなくデータベースも再検証するようにします。CLIをインストールして認証します。
npm install -g apidog-cli
apidog login --with-token <YOUR_ACCESS_TOKEN>
次に、構築したシナリオをIDで指定し、選択した環境に対して実行します。
apidog run --access-token $APIDOG_ACCESS_TOKEN -t <scenario_id> -e <env_id> -r cli
ここで -t はテストシナリオID、-e は環境ID、-r はレポーター(cli、html、または junit。複数指定する場合は -r html,cli のようにカンマで区切ります)です。計画すべきことの1つは、データベース接続の詳細はローカルにあるため、CIからデータベースにアクセスするにはエクスポートされた設定がランナーに必要になることです。データセットからシナリオの行を供給する場合、Apidog CLIによるデータ駆動型テストでは、各行が同じデータベースアサーションを実行する方法を示しており、ApidogによるAPIテストのスケジュール設定では、データベースアサーションの失敗が他のテストと同様に浮上するように、定期的に実行する方法を説明しています。
よくある質問
無料のデータベースと有料のデータベースはどれですか? MySQL、SQL Server(2014以降)、PostgreSQL、Oracleは無料プランで利用できます。ClickHouse、MongoDB、Redisは有料プランが必要です。MongoDBとRedisのドキュメントには、接続が有料機能であることが明記されているため、NoSQLスイートを計画する前に料金ページを確認してください。まず無料のデータベースを試すには、Apidogをダウンロードしてください。
データベースの値を後のリクエストで使用できますか? はい、可能です。データベース操作を含むポストプロセッサーを追加し、`SELECT` を実行した後、「結果を変数に抽出」を使用して、変数名と `$[0].fulfillment_ref` のようなJSONPath式で最初の行からフィールドを分離します。後で `{{variable_name}}` として参照できます。HTTPレスポンスの同様の連鎖のアイデアは、テストステップ間でデータを渡すでカバーされています。
チームメイトは自動的に私のデータベース接続を取得できますか? いいえ。接続の認証情報は各クライアントにローカルに保存され、クラウドには同期されません。そのため、各チームメンバーが自分で接続を設定します。これは意図的なもので、本番環境のパスワードが共有プロジェクトに漏れるのを防ぎます。
MySQL 8の接続が頻繁に失敗します。なぜですか? MySQL 8はデフォルトで `caching_sha2_password` 認証プラグインを使用しており、これが接続をブロックする場合があります。`ALTER USER ... IDENTIFIED WITH mysql_native_password` を使用してユーザーを `mysql_native_password` に切り替え、再接続してください。
ストアドプロシージャや複雑なデータベースロジックを実行できますか? ビジュアルインターフェースからはできません。標準のSELECT、INSERT、UPDATE、DELETEステートメントは処理しますが、ストアドプロシージャのような複雑な操作はサポートされていません。テストステップは直接的なステートメントに限定してください。
まとめ
データベースクエリは、APIテストを「レスポンスは正しく見えた」から「データは実際に正しい」へと変えます。プリプロセッサーで既知の状態をシードし、ポストプロセッサーで永続化された行を検証し、サーバー生成値を抽出して次のリクエストに連鎖させることができます。これらすべてを1つのシナリオ内で行えます。環境ごとに接続を設定すれば、同じステップをステージング環境やローカル環境に対して安全に、編集なしで実行できます。
無料で試しましょう(クレジットカードは不要です)。Apidogをダウンロードし、MySQL接続を開発データベースに向け、次のリクエストが作成する行を読み取るポストプロセッサーを1つ追加してみてください。
