api-testing-patterns
APIのコントラクトテスト、REST/GraphQLテスト、インテグレーションテストを網羅したテストパターン集です。APIのテスト実施やテスト戦略の設計が必要な際に活用してください。
description の原文を見る
Comprehensive API testing patterns including contract testing, REST/GraphQL testing, and integration testing. Use when testing APIs or designing API test strategies.
SKILL.md 本文
API テストパターン
<default_to_action> APIをテストまたはAPIテスト戦略を設計する場合:
- テストレベルを特定: コントラクト、統合、またはコンポーネント
- 実装ではなくコントラクトをテスト (消費者視点)
- 認証、入力、エラー、べき等性、並行性を検証
- CI/CDでスキーマ検証を自動化
- 本番APIでコントラクトドリフトを監視
クイックパターン選択:
- マイクロサービス → Consumer-driven contracts (Pact)
- REST API → CRUD + ページネーション + フィルタリングテスト
- GraphQL → クエリ検証 + 複雑性制限
- 外部依存 → コンポーネントテストでモック
- パフォーマンス → 重要エンドポイントの負荷テスト
成功の重要要因:
- APIはコントラクト - 消費者視点からテスト
- 常にエラーシナリオをテスト、ハッピーパスだけではなく
- API テストをバージョン管理して破壊的変更を防止 </default_to_action>
クイックリファレンスカード
使用時機
- REST または GraphQL APIをテスト
- マイクロサービスコントラクトを検証
- APIテスト戦略を設計
- API破壊的変更を防止
テストレベル
| レベル | 目的 | 依存関係 | 速度 |
|---|---|---|---|
| コントラクト | プロバイダー-消費者間の合意 | なし | 高速 |
| コンポーネント | 分離されたAPI | モック化 | 高速 |
| 統合 | 実際の依存関係 | データベース、サービス | 遅い |
重要なテストシナリオ
| シナリオ | テスト対象 | 例 |
|---|---|---|
| 認証 | 401/403の処理 | 期限切れトークン、不正なユーザー |
| 入力 | 400検証 | 必須フィールド欠落、型エラー |
| エラー | 500の適切な処理 | DB ダウン、タイムアウト |
| べき等性 | 重複防止 | 同じべき等性キー |
| 並行性 | レース条件 | 並列チェックアウト |
ツール
- コントラクト: Pact, Spring Cloud Contract
- REST: Supertest, REST-assured, Playwright
- 負荷: k6, Artillery, JMeter
エージェント連携
qe-api-contract-validator: コントラクト検証、破壊的変更検出qe-test-generator: OpenAPI スペックからテスト生成qe-performance-tester: エンドポイント負荷テストqe-security-scanner: API セキュリティテスト
コントラクトテスト
パターン: Consumer-Driven Contracts
// 消費者が期待を定義
const contract = {
request: { method: 'POST', path: '/orders', body: { productId: 'abc', quantity: 2 } },
response: { status: 201, body: { orderId: 'string', total: 'number' } }
};
// プロバイダーが満たす
test('order API がコントラクトを満たす', async () => {
const response = await api.post('/orders', { productId: 'abc', quantity: 2 });
expect(response.status).toBe(201);
expect(response.body).toMatchSchema({
orderId: expect.any(String),
total: expect.any(Number)
});
});
使用時機: マイクロサービス、分散システム、サードパーティー統合
重要なテストパターン
認証・認可
describe('認証', () => {
it('トークンなしで拒否', async () => {
expect((await api.get('/orders')).status).toBe(401);
});
it('期限切れトークンを拒否', async () => {
const expired = generateExpiredToken();
expect((await api.get('/orders', { headers: { Authorization: `Bearer ${expired}` } })).status).toBe(401);
});
it('ユーザー間のアクセスをブロック', async () => {
const userAToken = generateToken({ userId: 'A' });
expect((await api.get('/orders/user-B-order', { headers: { Authorization: `Bearer ${userAToken}` } })).status).toBe(403);
});
});
入力検証
describe('検証', () => {
it('必須フィールドを検証', async () => {
const response = await api.post('/orders', { quantity: 2 }); // productId がない
expect(response.status).toBe(400);
expect(response.body.errors).toContain('productId is required');
});
it('型を検証', async () => {
expect((await api.post('/orders', { productId: 'abc', quantity: 'two' })).status).toBe(400);
});
it('範囲を検証', async () => {
expect((await api.post('/orders', { productId: 'abc', quantity: -5 })).status).toBe(400);
});
});
べき等性
it('べき等性キーで重複を防止', async () => {
const key = 'unique-123';
const data = { productId: 'abc', quantity: 2 };
const r1 = await api.post('/orders', data, { headers: { 'Idempotency-Key': key } });
const r2 = await api.post('/orders', data, { headers: { 'Idempotency-Key': key } });
expect(r1.body.orderId).toBe(r2.body.orderId); // 同じ注文
});
並行性
it('在庫のレース条件を処理', async () => {
const promises = Array(10).fill().map(() =>
api.post('/orders', { productId: 'abc', quantity: 1 })
);
const responses = await Promise.all(promises);
const successful = responses.filter(r => r.status === 201);
const inventory = await db.inventory.findById('abc');
expect(inventory.quantity).toBe(initialQuantity - successful.length);
});
REST CRUD パターン
describe('Product CRUD', () => {
let productId;
it('作成', async () => {
const r = await api.post('/products', { name: 'Widget', price: 10 });
expect(r.status).toBe(201);
productId = r.body.id;
});
it('読み取り', async () => {
const r = await api.get(`/products/${productId}`);
expect(r.body.name).toBe('Widget');
});
it('更新', async () => {
const r = await api.put(`/products/${productId}`, { price: 12 });
expect(r.body.price).toBe(12);
});
it('削除', async () => {
expect((await api.delete(`/products/${productId}`)).status).toBe(204);
expect((await api.get(`/products/${productId}`)).status).toBe(404);
});
});
ベストプラクティス
✅ こうしましょう
- 消費者視点からテスト
- スキーマ検証を使用 (厳密な値ではなく)
- エラーシナリオを広範にテスト
- APIテストをバージョン管理
- CI/CDで自動化
❌ これは避けましょう
- 実装をテスト、コントラクトではなく
- HTTP セマンティクスを無視 (ステータスコード)
- ネガティブテストがない
- フィールド順序や余分なフィールドをアサート
- 遅いテスト (外部サービスをモック化)
エージェント支援型 API テスト
// コントラクト検証
await Task("コントラクト検証", {
spec: 'openapi.yaml',
endpoint: '/orders',
checkBreakingChanges: true
}, "qe-api-contract-validator");
// スペックからテスト生成
await Task("API テスト生成", {
spec: 'openapi.yaml',
coverage: 'comprehensive',
include: ['happy-paths', 'input-validation', 'auth-scenarios', 'error-handling']
}, "qe-test-generator");
// 負荷テスト
await Task("API 負荷テスト", {
endpoint: '/orders',
rps: 1000,
duration: '5min'
}, "qe-performance-tester");
// セキュリティスキャン
await Task("API セキュリティスキャン", {
spec: 'openapi.yaml',
checks: ['sql-injection', 'xss', 'broken-auth', 'rate-limiting']
}, "qe-security-scanner");
エージェント連携ヒント
メモリネームスペース
aqe/api-testing/
├── contracts/* - API コントラクト定義
├── generated-tests/* - 生成されたテストスイート
├── validation/* - コントラクト検証結果
└── performance/* - 負荷テスト結果
フリート連携
const apiFleet = await FleetManager.coordinate({
strategy: 'contract-testing',
agents: ['qe-api-contract-validator', 'qe-test-generator', 'qe-test-executor'],
topology: 'mesh'
});
await apiFleet.execute({
services: [
{ name: 'orders-api', consumers: ['checkout-ui', 'admin-api'] },
{ name: 'payment-api', consumers: ['orders-api'] }
]
});
関連スキル
agentic-quality-engineering- エージェント付き API テストtdd-london-chicago- API テストのロンドンスクールperformance-testing- API 負荷テストsecurity-testing- API セキュリティ検証contract-testing- Consumer-driven コントラクト詳細解説
覚えておくこと
API テスト = 実装ではなくコントラクトと動作の検証。消費者にとって重要なもの: 正確なレスポンス、適切なエラー処理、許容可能なパフォーマンスに焦点を当てる。
エージェント付き: エージェントはコントラクト検証を自動化し、スペックから包括的なテストスイートを生成し、本番APIのドリフトを監視します。エージェントを使用してスケールでAPI品質を維持します。
落とし穴
- エージェントは文書化されたAPIに対してテストを生成します。実際のAPIではありません — 常に実行中のサービスに対して最初に検証します
- 認証トークンはテスト実行間で期限切れになります — 長期的なトークンを持つフィクスチャを使用するか、各スイート前にリフレッシュ
- CI の レート制限により断続的な失敗が発生します — 429 レスポンスに対して指数バックオフで再試行を追加
- GraphQL イントロスペクションは本番で無効になる場合があります — 本番エンドポイントではなくステージング スキーマに対してテスト
- べき等性テストは実行ごとに一意のリクエストIDが必要です — ハードコードされたIDは再試行で誤検が起こります
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- proffesor-for-testing
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/proffesor-for-testing/agentic-qe / ライセンス: MIT
関連スキル
doubt-driven-development
重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。
apprun-skills
TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。
desloppify
コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。
debugging-and-error-recovery
テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。
test-driven-development
テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。
incremental-implementation
変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。