ai-regression-testing
AIを活用した開発における回帰テスト戦略を提供するスキルです。データベース不要のサンドボックス方式でAPIテストを実施し、欠陥検出ワークフローを自動化するとともに、同一モデルがコードの記述とレビューを行う際に生じやすいAIの盲点を捉えるパターンを組み込んでいます。
description の原文を見る
AI辅助开发的回归测试策略。沙盒模式API测试,无需依赖数据库,自动化的缺陷检查工作流程,以及捕捉AI盲点的模式,其中同一模型编写和审查代码。
SKILL.md 本文
AI 回帰テスト
AI エージェント(Claude Code、Cursor、Codex)がコードを作成し、その後それを審査する場合に発生する体系的なブラインドスポットを発見するためにのみ自動化テストが対応できる、AI 支援開発専用のテストパターン。
いつ有効化するか
- AI エージェント(Claude Code、Cursor、Codex)が API ルートまたはバックエンドロジックを変更した
- バグが見つかって修正された——再導入を防ぐ必要がある
- プロジェクトにはサンドボックス/モックモードがあり、データベースなしでテストに使用できる
- コード変更後に
/bug-checkまたは類似のレビューコマンドを実行する - 複数のコードパス(サンドボックス vs 本番環境、機能フラグなど)が存在する
中核的な問題
AI がコードを作成してから自分の作業をレビューすると、同じ仮定を両方のステップに持ち込みます。これにより予測可能な失敗パターンが形成されます:
AI が修正を作成 → AI が修正をレビュー → AI が「正しく見える」と言う → 脆弱性は残存
実際の例(本番環境で観察):
修正 1:API レスポンスに notification_settings を追加
→ SELECT クエリに追加するのを忘れた
→ AI レビュー時に見落とされた(同じブラインドスポット)
修正 2:SELECT クエリに追加
→ TypeScript ビルドエラー(列が生成型に含まれていない)
→ AI が修正 1 をレビューしたが SELECT の問題を見つけられなかった
修正 3:代わりに SELECT * に変更
→ 本番パスを修正し、サンドボックスパスを忘れた
→ AI レビュー時に再び見落とされた(4 回目)
修正 4:テストが初回実行時に即座に問題をキャッチ PASS:
パターン:サンドボックス/本番環境パスの不一致は AI が導入する #1 回帰問題です。
サンドボックスモード API テスト
AI フレンドリーアーキテクチャを持つほとんどのプロジェクトにはサンドボックス/モックモードがあります。これは高速でデータベース不要の API テストを実装するための鍵です。
セットアップ(Vitest + Next.js App Router)
// vitest.config.ts
import { defineConfig } from "vitest/config";
import path from "path";
export default defineConfig({
test: {
environment: "node",
globals: true,
include: ["__tests__/**/*.test.ts"],
setupFiles: ["__tests__/setup.ts"],
},
resolve: {
alias: {
"@": path.resolve(__dirname, "."),
},
},
});
// __tests__/setup.ts
// Force sandbox mode — no database needed
process.env.SANDBOX_MODE = "true";
process.env.NEXT_PUBLIC_SUPABASE_URL = "";
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY = "";
Next.js API ルートのテストヘルパー
// __tests__/helpers.ts
import { NextRequest } from "next/server";
export function createTestRequest(
url: string,
options?: {
method?: string;
body?: Record<string, unknown>;
headers?: Record<string, string>;
sandboxUserId?: string;
},
): NextRequest {
const { method = "GET", body, headers = {}, sandboxUserId } = options || {};
const fullUrl = url.startsWith("http") ? url : `http://localhost:3000${url}`;
const reqHeaders: Record<string, string> = { ...headers };
if (sandboxUserId) {
reqHeaders["x-sandbox-user-id"] = sandboxUserId;
}
const init: { method: string; headers: Record<string, string>; body?: string } = {
method,
headers: reqHeaders,
};
if (body) {
init.body = JSON.stringify(body);
reqHeaders["content-type"] = "application/json";
}
return new NextRequest(fullUrl, init);
}
export async function parseResponse(response: Response) {
const json = await response.json();
return { status: response.status, json };
}
回帰テストの作成
重要な原則:正常に動作するコードのテストではなく、発見されたバグのテストを作成する。
// __tests__/api/user/profile.test.ts
import { describe, it, expect } from "vitest";
import { createTestRequest, parseResponse } from "../../helpers";
import { GET, PATCH } from "@/app/api/user/profile/route";
// Define the contract — what fields MUST be in the response
const REQUIRED_FIELDS = [
"id",
"email",
"full_name",
"phone",
"role",
"created_at",
"avatar_url",
"notification_settings", // ← Added after bug found it missing
];
describe("GET /api/user/profile", () => {
it("returns all required fields", async () => {
const req = createTestRequest("/api/user/profile");
const res = await GET(req);
const { status, json } = await parseResponse(res);
expect(status).toBe(200);
for (const field of REQUIRED_FIELDS) {
expect(json.data).toHaveProperty(field);
}
});
// Regression test — this exact bug was introduced by AI 4 times
it("notification_settings is not undefined (BUG-R1 regression)", async () => {
const req = createTestRequest("/api/user/profile");
const res = await GET(req);
const { json } = await parseResponse(res);
expect("notification_settings" in json.data).toBe(true);
const ns = json.data.notification_settings;
expect(ns === null || typeof ns === "object").toBe(true);
});
});
サンドボックス/本番環境の一貫性をテストする
最も一般的な AI 回帰問題:本番環境パスは修正したがサンドボックスパスを忘れた(またはその逆)。
// Test that sandbox responses match the expected contract
describe("GET /api/user/messages (conversation list)", () => {
it("includes partner_name in sandbox mode", async () => {
const req = createTestRequest("/api/user/messages", {
sandboxUserId: "user-001",
});
const res = await GET(req);
const { json } = await parseResponse(res);
// This caught a bug where partner_name was added
// to production path but not sandbox path
if (json.data.length > 0) {
for (const conv of json.data) {
expect("partner_name" in conv).toBe(true);
}
}
});
});
テストをバグチェックワークフローに統合する
カスタムコマンド定義
<!-- .claude/commands/bug-check.md -->
# Bug チェック
## ステップ 1:自動テスト(必須、スキップ不可)
コードレビューの**前に**最初に以下のコマンドを実行します:
npm run test # Vitest テストスイート
npm run build # TypeScript 型チェック + ビルド
- テストが失敗 → 最優先度 Bug として報告
- ビルドが失敗 → 型エラーを最優先度として報告
- 両方が成功したときのみステップ 2 に進む
## ステップ 2:コードレビュー(AI レビュー)
1. サンドボックス/本番環境パスの一貫性
2. API レスポンス構造がフロントエンド期待値と一致しているか
3. SELECT 句の完全性
4. ロールバックを含むエラーハンドリング
5. オプティミスティック更新の競合状態
## ステップ 3:修正された各バグについて、回帰テスト戦略を提案する
ワークフロー
User: "/bug-check" を実行
│
├─ ステップ 1: npm run test
│ ├─ 失敗 → 機械的エラーを検出(AI 判断不要)
│ └─ 成功 → 続行
│
├─ ステップ 2: npm run build
│ ├─ 失敗 → 型エラーを検出
│ └─ 成功 → 続行
│
├─ ステップ 3:AI コードレビュー(既知のブラインドスポットを考慮)
│ └─ 見つかった問題を報告
│
└─ ステップ 4:修正ごとに回帰テストを作成
└─ 次の bug-check で修正が機能を破壊していないかをキャッチ
よくある AI 回帰パターン
パターン 1:サンドボックス/本番環境パスのミスマッチ
頻度:最も一般的(4 つの回帰問題中 3 つで観察)
// 失敗:AI が本番環境パスのみにフィールドを追加
if (isSandboxMode()) {
return { data: { id, email, name } }; // Missing new field
}
// Production path
return { data: { id, email, name, notification_settings } };
// 成功:両方のパスが同じ形を返す必要がある
if (isSandboxMode()) {
return { data: { id, email, name, notification_settings: null } };
}
return { data: { id, email, name, notification_settings } };
これをキャッチするテスト:
it("sandbox and production return same fields", async () => {
// In test env, sandbox mode is forced ON
const res = await GET(createTestRequest("/api/user/profile"));
const { json } = await parseResponse(res);
for (const field of REQUIRED_FIELDS) {
expect(json.data).toHaveProperty(field);
}
});
パターン 2:SELECT 句の遺漏
頻度:Supabase/Prisma で新しい列を追加する場合に一般的
// 失敗:新しい列がレスポンスに追加されたが SELECT に追加されていない
const { data } = await supabase
.from("users")
.select("id, email, name") // notification_settings not here
.single();
return { data: { ...data, notification_settings: data.notification_settings } };
// → notification_settings is always undefined
// 成功:SELECT * を使用するか新しい列を明示的に含める
const { data } = await supabase
.from("users")
.select("*")
.single();
パターン 3:エラー状態のリーク
頻度:中程度——既存のコンポーネントにエラーハンドリングを追加する場合
// 失敗:エラー状態が設定されるが古いデータがクリアされない
catch (err) {
setError("Failed to load");
// reservations still shows data from previous tab!
}
// 成功:エラー時に関連する状態をクリアする
catch (err) {
setReservations([]); // Clear stale data
setError("Failed to load");
}
パターン 4:オプティミスティック更新の不正なロールバック
// 失敗:失敗時のロールバックなし
const handleRemove = async (id: string) => {
setItems(prev => prev.filter(i => i.id !== id));
await fetch(`/api/items/${id}`, { method: "DELETE" });
// If API fails, item is gone from UI but still in DB
};
// 成功:前の状態をキャプチャし失敗時にロールバック
const handleRemove = async (id: string) => {
const prevItems = [...items];
setItems(prev => prev.filter(i => i.id !== id));
try {
const res = await fetch(`/api/items/${id}`, { method: "DELETE" });
if (!res.ok) throw new Error("API error");
} catch {
setItems(prevItems); // Rollback
alert("削除に失敗しました");
}
};
戦略:バグが見つかった場所でテストする
100% のカバレッジを追い求めないでください。代わりに:
/api/user/profile でバグが見つかった → profile API のテストを作成
/api/user/messages でバグが見つかった → messages API のテストを作成
/api/user/favorites でバグが見つかった → favorites API のテストを作成
/api/user/notifications でバグが見つからなかった → 今のところテストを作成しない
これが AI 開発で機能する理由:
- AI は同じ種類のエラーを繰り返す傾向がある
- バグは複雑な領域(認証、マルチパスロジック、状態管理)に集中している
- テストされれば、その特定の回帰問題は二度と発生しない
- テスト数はバグ修正に応じて有機的に増える——無駄な努力なし
クイックリファレンス
| AI 回帰パターン | テスト戦略 | 優先度 |
|---|---|---|
| サンドボックス/本番環境のミスマッチ | サンドボックスモード下でレスポンス構造が同じであることをアサート | 高 |
| SELECT 句の遺漏 | レスポンスに全必須フィールドが含まれていることをアサート | 高 |
| エラー状態のリーク | エラー時に状態がクリアされていることをアサート | 中 |
| ロールバックの欠落 | API 失敗時に状態が復元されていることをアサート | 中 |
| 型変換が null をマスク | フィールドが undefined でないことをアサート | 中 |
すべき/してはいけない
すべき:
- バグを発見した直後にテストを作成する(可能であれば修正の前に)
- 実装の詳細ではなく API レスポンス構造をテストする
- テスト実行を各バグチェックの第一ステップにする
- テストは高速に保つ(サンドボックスモード全体で < 1 秒)
- テストが防止するバグに基づいてテストに名前を付ける(例:「BUG-R1 regression」)
してはいけない:
- バグが発生したことのないコードのテストを作成する
- AI 自己レビューが自動化テストの代わりになると信じる
- 「ただのモックデータ」だからサンドボックスパステストをスキップする
- ユニットテストで十分な場合は統合テストを作成する
- カバレッジの割合を追い求める——回帰予防を追い求める
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- affaan-m
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/affaan-m/everything-claude-code / ライセンス: MIT
関連スキル
agent-browser
AI エージェント向けのブラウザ自動化 CLI です。ウェブサイトとの対話が必要な場合に使用します。ページ遷移、フォーム入力、ボタンクリック、スクリーンショット取得、データ抽出、ウェブアプリのテスト、ブラウザ操作の自動化など、あらゆるブラウザタスクに対応できます。「ウェブサイトを開く」「フォームに記入する」「ボタンをクリックする」「スクリーンショットを取得する」「ページからデータを抽出する」「このウェブアプリをテストする」「サイトにログインする」「ブラウザ操作を自動化する」といった要求や、プログラマティックなウェブ操作が必要なタスクで起動します。
anyskill
AnySkill — あなたのプライベート・スキルクラウド。GitHubを基盤としたリポジトリからエージェントスキルを管理、同期、動的にロードできます。自然言語でクラウドスキルを検索し、オンデマンドでプロンプトを自動ロード、カスタムスキルのアップロードと共有、スキルバンドルの一括インストールが可能です。OpenClaw、Antigravity、Claude Code、Cursorに対応しています。
engram
AIエージェント向けの永続的なメモリシステムです。バグ修正、意思決定、発見、設定変更の後はmem_saveを使用してください。ユーザーが「覚えている」「記憶している」と言及した場合、または以前のセッションと重複する作業を開始する際はmem_searchを使用します。セッション終了前にmem_session_summaryを使用して、コンテキストを保持してください。
skyvern
AI駆動のブラウザ自動化により、任意のウェブサイトを自動化できます。フォーム入力、データ抽出、ファイルダウンロード、ログイン、複数ステップのワークフロー実行など、ユーザーがウェブサイトと連携する必要があるときに使用します。Skyvernは、LLMとコンピュータビジョンを活用して、未知のサイトも自動操作可能です。Python SDK、TypeScript SDK、REST API、MCPサーバー、またはCLIを通じて統合できます。
pinchbench
PinchBenchベンチマークを実行して、OpenClawエージェントの実世界タスクにおけるパフォーマンスを評価できます。モデルの機能テスト、モデル間の比較、ベンチマーク結果のリーダーボード提出、またはOpenClawのセットアップがカレンダー、メール、リサーチ、コーディング、複数ステップのワークフローにどの程度対応しているかを確認する際に使用します。
openui
OpenUIとOpenUI Langを使用してジェネレーティブUIアプリを構築できます。これらはLLM生成インターフェースのためのトークン効率的なオープン標準です。OpenUI、@openuidev、ジェネレーティブUI、LLMからのストリーミングUI、AI向けコンポーネントライブラリ、またはjson-render/A2UIの置き換えについて述べる際に使用します。スキャフォルディング、defineComponent、システムプロンプト、Renderer、およびOpenUI Lang出力のデバッグに対応しています。