
关于
AI 辅助开发的回归测试策略。包括无数据库依赖的沙箱模式 API 测试、自动化缺陷检查工作流,以及针对同一模型编写和审查代码时盲点的检测模式。
name: ai-regression-testing description: AI辅助开发的回归测试策略。无数据库依赖的沙箱模式API测试、自动化Bug检查工作流,以及捕获AI盲点的模式——当同一模型既编写又审查代码时产生的盲点。 origin: ECC
AI 回归测试
专为AI辅助开发设计的测试模式——当同一模型既编写代码又审查代码时,会产生系统性盲点,只有自动化测试才能捕获。
何时启用
- AI代理(Claude Code、Cursor、Codex)修改了API路由或后端逻辑
- 发现并修复了Bug——需要防止再次引入
- 项目有沙箱/模拟模式可用于无数据库测试
- 代码变更后运行
/bug-check或类似审查命令 - 存在多条代码路径(沙箱 vs 生产、功能开关等)
核心问题
当AI编写代码然后审查自己的工作时,它会将相同的假设带入两个步骤。这会产生可预测的失败模式:
AI编写修复 → AI审查修复 → AI说"看起来正确" → Bug仍然存在
真实案例(在生产环境中观察到):
修复1: 将 notification_settings 添加到API响应
→ 忘记添加到 SELECT 查询中
→ AI审查时遗漏(相同盲点)
修复2: 添加到 SELECT 查询
→ TypeScript构建错误(列不在生成的类型中)
→ AI审查了修复1但没有发现 SELECT 问题
修复3: 改为 SELECT *
→ 修复了生产路径,忘记了沙箱路径
→ AI审查时再次遗漏(第4次出现)
修复4: 测试在首次运行时立即捕获 通过:
规律:沙箱/生产路径不一致是AI引入的第一大回归问题。
沙箱模式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
// 强制沙箱模式——无需数据库
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 };
}
编写回归测试
核心原则:为发现的Bug编写测试,而不是为正常工作的代码编写测试。
// __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";
// 定义契约——响应中必须包含的字段
const REQUIRED_FIELDS = [
"id",
"email",
"full_name",
"phone",
"role",
"created_at",
"avatar_url",
"notification_settings", // ← 发现Bug后添加
];
describe("GET /api/user/profile", () => {
it("返回所有必需字段", 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);
}
});
// 回归测试——这个Bug被AI引入了4次
it("notification_settings 不为 undefined(BUG-R1 回归)", 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);
});
});
兼容工具
Claude CodeCursor
标签
AI与机器学习
