MF Blogs 便利ツール
API・DB・テストのつながりを示す抽象図

記事

Claude CodeでAPI・DB連携テストを作るときのポイント

Claude Codeに結合テスト(インテグレーションテスト)を書かせるときに押さえるポイントを整理します。テストDBの選択、モック方針、外部API、シードデータ、後片付け、CI連携までを依頼文テンプレートとともに扱います。

0:00 0:00

ユニットテストと違い、APIエンドポイント・DB・外部サービスを含む結合テストは「何をモックして何を実物で動かすか」の設計が結果を左右します。Claude Codeに結合テストを書かせるとき、観点を渡さないと「mockだらけで通るが本番では落ちるテスト」になりがちです。この記事では、APIとDBを含む結合テストを作るときの設計判断と依頼文テンプレートを整理します。

モックする層を最初に決める

結合テストの最大の論点は「何をモックして何を実物で動かすか」です。次の3層モデルで考えると判断が安定します。

推奨
DB層PostgreSQL、MySQL、SQLite実物を使う(Testcontainersなど)
外部API層Stripe、Slack、SendGridモックを使う(msw、nock)
アプリケーション層自分が書いた関数実物を使う

DBをモックすると本番のSQL不整合が検出できません。外部APIを実物で叩くと課金や通信コストが発生します。この方針を依頼文とCLAUDE.mdに書いておけば、AIが勝手にDBをモックすることを防げます。

CLAUDE.mdに書く結合テストルール

## 結合テストルール

- DBは実物を使う(テスト用DBコンテナまたはローカルテスト用インスタンス)
- 外部APIはモックする(msw / nock / 自前のスタブ)
- 課金・送信系(Stripe、SendGrid、Twilio)は絶対に実物を叩かない
- テスト前にシードデータを投入し、テスト後に必ずロールバックまたはトランザクション破棄する
- テスト用の認証トークンは固定値を使い、コードに直書きしない(環境変数)
- フィクスチャは tests/fixtures/ に集約する

CLAUDE.mdの書き方の詳細は「CLAUDE.mdテンプレート完全版」を参照してください。

テストDBの3つの選び方

1. Testcontainersで本番同種のDBを起動

Testcontainersは、Dockerコンテナでテスト用DBを起動するライブラリです。本番と同じバージョンのPostgreSQLやMySQLを使えるため、SQL方言の違いによる事故を防げます。CIでDockerが使えるなら第一選択です。

2. ローカル開発DBをトランザクション分離で使う

Dockerで常駐させたDBに対して、各テストをトランザクションで囲み、最後にロールバックする方式です。テストの並列実行に注意が必要ですが、起動が速いメリットがあります。

3. SQLite等の軽量DBで代替

開発初期で本番DB方言依存が無い段階なら、SQLiteのインメモリDBで結合テストを書く選択肢もあります。ただしJSON型・ウィンドウ関数・特殊なインデックスなどを使うなら本番と同じDBに切り替えるべきです。

API結合テストの依頼文テンプレート

依頼:POST /api/users エンドポイントの結合テストを書いてください。

## 観点
- 正常系:正しいリクエストでユーザーが作成され、DBに保存される
- 異常系1:必須フィールド欠損で 400 が返る
- 異常系2:重複メールアドレスで 409 が返る
- 異常系3:外部メール送信APIが失敗してもユーザー作成自体は成功する

## モック方針
- DB:実物(テストコンテナ)を使う
- メール送信API:msw でモック化、成功時/失敗時の両方をテスト
- 認証:テスト用固定トークンで通す

## セットアップ
- 各テストの beforeEach で DB をクリーンにする
- フィクスチャは tests/fixtures/users.ts から読み込む

## 完了条件
- すべてのテストが通る
- npx tsc --noEmit がエラーなしで通る
- テスト後に DB に余分なレコードが残らない
- 外部 API の実物には1回もアクセスしないこと

「外部APIに1回もアクセスしないこと」を完了条件に入れるのがポイントです。テスト実行ログでmswのintercept件数を確認できます。

DB結合テストでよくある失敗パターン

症状原因対処
単体では通るが連続実行で落ちるbeforeEachのクリーンアップ漏れトランザクション分離またはtruncate
CIだけ落ちる並列実行で同一レコードを取り合うテストごとに独立スキーマか、describe.serialで直列化
nullundefinedになるORM経由で型が変換されているDB直接クエリで実値を確認
マイグレーション漏れに気づかないテストDBに最新スキーマが当たっていないbeforeAllでmigrate実行

外部APIモックの依頼文テンプレート

依頼:Stripe決済APIの結合テストを書いてください。

## 制約
- Stripe本番にも sandbox にも一切アクセスしないこと
- msw で /v1/charges のレスポンスをモック化する
- 成功レスポンス(200)と失敗レスポンス(402 card_declined)の両方をテストする
- モックレスポンスは tests/fixtures/stripe.ts に定義する

## 観点
- 正常決済時に DB の order.status が paid になる
- card_declined 時に order.status が failed になり、失敗理由が記録される
- ネットワーク例外時にリトライが3回行われる

## 完了条件
- 実 Stripe API へのアクセスが0件であることをテストログで確認できる
- DB の状態がテストごとに独立していること

Stripeなどの課金系APIは、テストモードであっても本番アカウントの状態を汚す可能性があります。明示的にモック必須と書いておきます。

シードデータと後片付け

テストデータの管理は次の2点を決めれば破綻しにくくなります。

シードデータは関数経由で作る

ハードコードした巨大なJSONより、ファクトリー関数のほうがメンテナンスしやすくなります。

// tests/fixtures/users.ts
export const buildUser = (overrides = {}) => ({
  id: crypto.randomUUID(),
  email: `test-${Date.now()}@example.com`,
  name: "Test User",
  ...overrides,
});

依頼文で「フィクスチャはbuild関数を作る」と指定すると、AIも一貫した形で生成します。

後片付けはトランザクションロールバックを優先

beforeEachでtruncateするより、テスト全体をトランザクションで囲んでロールバックする方がシンプルかつ高速です。フレームワークによってはテストハーネスが対応しています(Prismaの$transactionなど)。

CI連携の最低条件

CIで結合テストを動かす場合、最低限次を整えます。

  • DB起動を待ってからテストを開始する(pg_isreadyなどのヘルスチェック)
  • テスト用シークレットはGitHub ActionsのSecretsで注入し、コードに直書きしない
  • 失敗時にDBログとアプリログを成果物として保存する
  • テスト時間がCI予算を超えないよう、結合テストは並列化または分割実行する

シークレット管理は「Claude Codeに秘密情報を渡さないための実践ルール」を参照してください。

AIが書きがちな危ないテスト

AIが生成する結合テストで頻出する問題パターンです。レビューで弾きます。

  1. DBを丸ごとモックしている: jest.mockでORM全体をmock化し、SQLが一切走らない
  2. アサートがexpect(true).toBe(true)相当: 戻り値の存在だけ確認している
  3. モックレスポンスが本物と違う形: 本番APIにない構造を返してテストが通る
  4. any型でレスポンスを受けている: 型安全性が抜ける
  5. 後片付けがない: テストの度にDBレコードが累積する
  6. describe.skipが混入: 通らないテストをスキップで放置

ユニットテストの危ないサインも含めて「Claude Codeにテストコードを生成させるときの依頼文と注意点」で詳しく扱っています。

結合テスト依頼前のチェックリスト

  • DB・外部API・アプリ層のモック方針を明示したか
  • テスト観点(正常・異常)を3〜5個リストアップしたか
  • 「実APIにアクセスしないこと」を完了条件に入れたか
  • シードデータの場所(tests/fixtures/等)を指定したか
  • 後片付けの方針(truncate / トランザクションロールバック)を決めたか
  • 認証トークンを環境変数化する指定をしたか
  • CIで実行する場合のシークレット管理を確認したか

次に読むおすすめ記事: