Skip to content

03 - 测试验证食谱

用 AI 高效生成测试用例,从单元测试到端到端验证全覆盖。

适用场景

场景何时使用对应食谱
新功能写完需要测试覆盖每个 Service 函数完成后食谱 1
API 链路需要端到端验证每个 API Route 完成后食谱 2
现有测试缺少边界覆盖审查时发现覆盖不足食谱 3
依赖外部服务需要隔离涉及数据库、三方 API食谱 4
修复 Bug 需要回归保障每次 Bug 修复食谱 5
核心用户路径需要验证发布前、核心流程变更后食谱 6

食谱 1:单元测试生成

场景描述

为 Service 层函数生成单元测试。重点测试输入输出契约,不测试内部实现细节。遵循基于接口合同写测试的原则。

核心模板

text
为 {{目标文件}} 中的 {{函数名}} 生成单元测试。

技术栈:{{测试框架}}(如 Vitest / Jest / pytest)
测试文件位置:{{测试文件路径}}

要求:
1. 参考 {{现有测试文件}} 的风格和 describe/it 结构
2. 覆盖三类场景:
   - 正常路径:标准输入 → 期望输出
   - 边界条件:空值、空数组、极大值、特殊字符
   - 错误路径:无效输入、抛异常的情况
3. 每个 it 块描述清楚"输入什么 → 期望什么"
4. 不要 mock 被测函数的内部实现,只 mock 外部依赖
5. 写完后运行 {{测试命令}} 确认全绿

变量说明

变量说明示例
{{目标文件}}被测源文件路径src/services/order.service.ts
{{函数名}}具体函数或"所有导出函数"calculateTotal
{{测试框架}}项目使用的测试框架Vitest / Jest / pytest
{{测试文件路径}}测试文件存放位置src/services/__tests__/order.service.test.ts
{{现有测试文件}}已有测试文件作为风格参考src/services/__tests__/user.service.test.ts
{{测试命令}}执行测试的命令npm run test -- --run order.service

好坏对比

给 order.service.ts 写测试。 — 框架、风格、覆盖场景全部未知。

精准请求

text
为 src/services/order.service.ts 中的 calculateTotal 生成 Vitest 单元测试。
测试文件:src/services/__tests__/order.service.test.ts
参考 user.service.test.ts 的风格。
覆盖:正常计算、空购物车、单价为 0、数量为负数、超大金额溢出。
不要 mock 内部私有函数。写完运行 npm run test -- --run order.service。

实战案例

text
为 src/services/auth.service.ts 中的 registerUser 生成 Vitest 单元测试。
测试文件:src/services/__tests__/auth.service.test.ts
参考风格:src/services/__tests__/user.service.test.ts

覆盖场景:
- 正常注册:合法邮箱+密码 → 返回用户对象(不含密码)
- 邮箱已存在 → ConflictError
- 密码不足 8 位 / 邮箱格式非法 / 空字符串 → ValidationError

Mock:prisma.user.findUnique 和 prisma.user.create
不要 Mock:bcrypt.hash(用真实哈希验证)
写完运行 npm run test -- --run auth.service

Claude 增强 💡

text
读取 @src/services/order.service.ts 和 @src/services/__tests__/user.service.test.ts,
为 order.service.ts 的所有导出函数生成相同风格的单元测试。
覆盖正常路径、边界条件、错误路径。写完跑测试。

配合 /test Skill 可一键触发标准化测试生成流程。


食谱 2:集成测试设计

场景描述

验证 API Route 的完整请求→响应链路。集成测试关注组件协作是否正确,涵盖数据库交互、服务间调用等真实依赖。

核心模板

text
为 {{API路径}} 编写集成测试。

技术栈:{{测试框架}} + {{HTTP测试库}}
测试文件:{{测试文件路径}}

API 规格:
- 方法:{{HTTP方法}}
- 请求体:{{请求体结构}}
- 成功响应:{{成功响应结构}}
- 错误码:{{错误码列表}}

测试场景:
1. 正常请求 → 正确状态码 + 响应体
2. 缺少必填字段 → 400
3. 未认证 → 401 / 无权限 → 403 / 不存在 → 404
4. 数据库约束冲突 → 409
5. 参考 {{现有集成测试}} 的 setup/teardown 模式

数据准备:beforeAll seed 测试数据,afterAll 清理
写完运行 {{测试命令}}

变量说明

变量说明示例
{{API路径}}被测路由POST /api/orders
{{测试框架}} + {{HTTP测试库}}测试技术栈Vitest + supertest
{{请求体结构}} / {{成功响应结构}}请求与响应格式{ items: OrderItem[] }{ id, total }
{{错误码列表}}需覆盖的错误码400, 401, 403, 404, 409
{{现有集成测试}}已有测试参考tests/api/users.test.ts

好坏对比

测试 POST /api/orders 能正常创建订单。 — 只覆盖 happy path,遗漏错误分支。

覆盖完整链路

text
为 POST /api/orders 编写 Vitest + supertest 集成测试。
覆盖:正常创建→201、items 为空→400、未登录→401、
优惠券过期→400、库存不足→409。
参考 tests/api/users.test.ts 的 setup/teardown。

实战案例

text
为 POST /api/auth/login 编写集成测试。
技术栈:Vitest + supertest,测试文件:tests/api/auth-login.test.ts

场景:
- 正确邮箱+密码 → 200 + { token, user }
- 邮箱不存在 / 密码错误 → 401(不泄露具体原因)
- 缺少 email 字段 → 400 + zod 校验错误
- 账户被锁定 → 403
beforeAll seed 测试用户,afterAll 清理

Claude 增强 💡

text
读取 @src/app/api/orders/route.ts 和 @tests/api/users.test.ts,
为 orders API 生成相同模式的集成测试。覆盖所有状态码分支。写完跑测试。

食谱 3:边界条件穷举

场景描述

测试缺少边界覆盖时,让 AI 系统性穷举边界用例,再人工筛选。核心策略:让 AI 穷举,人来决策

核心模板

text
分析 {{目标函数}} 的所有边界条件,生成补充测试。

当前测试文件:{{现有测试文件}}
已覆盖场景:{{已有场景列表}}

请从以下维度穷举边界:
1. 数值:0、1、-1、MAX_SAFE_INTEGER、NaN、Infinity
2. 字符串:空串、纯空格、超长(10万字符)、特殊字符、Unicode/emoji
3. 集合:空数组、单元素、超大集合、含 null/undefined 元素
4. 类型:undefined、null、类型不匹配(传 string 给 number 参数)
5. 业务:{{业务特有的边界条件}}
6. 并发:同时调用是否安全、竞态条件

先列出清单,我确认后再写测试代码。

变量说明

变量说明示例
{{目标函数}}需补充边界测试的函数parseUserInput(raw: string)
{{现有测试文件}}已有测试文件src/__tests__/parser.test.ts
{{已有场景列表}}已覆盖的测试场景"正常输入、空输入"
{{业务特有的边界条件}}领域特殊边界"价格 0.001 元(小于最小支付单位)"

好坏对比

再多写几个测试用例。 — AI 不知道该从什么维度补充。

结构化穷举

text
分析 calculateDiscount(price, vipLevel) 的边界条件。
已覆盖:正常价格+正常等级、price=0。
未覆盖维度请穷举:数值边界(负数、小数精度、溢出)、
业务边界(VIP 等级范围外值、折扣超过原价)、
类型异常(NaN、undefined)。先列清单,我确认后写测试。

实战案例

text
分析 src/utils/pagination.ts 中 parsePagination(query) 的边界条件。
已有测试只覆盖了:page=1&limit=10 和 page=-1

请穷举:
1. page=0、page=999999、page=1.5、page=NaN
2. limit=0、limit=1、limit=1000、limit=-1
3. query 完全缺少 page/limit 参数
4. page="abc"(非数字字符串)

先列清单让我确认,再生成 Vitest 测试代码。

Claude 增强 💡

text
读取 @src/utils/pagination.ts 和 @src/utils/__tests__/pagination.test.ts,
找出还没覆盖的边界条件,列出清单。等我确认后再补充测试。

食谱 4:Mock 与 Stub 构造

场景描述

被测代码依赖数据库、三方 API 等外部服务时,构造合适的 Mock/Stub。核心原则:Mock 外部依赖,不 Mock 被测对象本身

核心模板

text
为 {{目标函数}} 的测试构造 Mock 和 Stub。

技术栈:{{测试框架}}
被测文件:{{被测文件路径}}
外部依赖:{{依赖清单}}

Mock 要求:
1. 只 Mock 上述外部依赖,被测函数内部逻辑不做 Mock
2. 每个 Mock 提供成功和失败两套返回值
3. Mock 数据使用 {{数据工厂方式}}
4. 参考 {{现有Mock模式}} 的组织方式
5. afterEach 中 restoreAllMocks,避免测试间污染
6. 时间相关用 vi.useFakeTimers() / freezegun

变量说明

变量说明示例
{{目标函数}}被测函数createOrder(input)
{{测试框架}}测试框架Vitest / Jest / pytest
{{被测文件路径}}源文件路径src/services/order.service.ts
{{依赖清单}}需 Mock 的外部依赖prisma.order.create, stripe.charges.create
{{数据工厂方式}}测试数据构建方式faker.js 工厂函数 / 手动字面量
{{现有Mock模式}}已有 Mock 参考tests/__mocks__/prisma.ts

好坏对比

Mock 掉 createOrder 里所有函数调用。 — Mock 了内部实现,重构即碎。

精准 Mock 外部边界

text
为 createOrder 测试构造 Mock:
- prisma.order.create → 成功返回 Order,失败抛 PrismaClientKnownRequestError
- stripe.charges.create → 成功返回 charge,失败抛 StripeCardError
- 不要 Mock calculateTotal、validateItems 等内部函数
用 vi.spyOn 实现,afterEach 中 vi.restoreAllMocks()

实战案例

text
为 src/services/payment.service.ts 中的 processPayment 构造 Vitest Mock。
外部依赖:prisma.payment.create、stripe.paymentIntents.create、emailService.sendReceipt
每个依赖提供成功 + 失败两套 Mock 数据。
用 vi.spyOn + mockResolvedValue / mockRejectedValue,afterEach vi.restoreAllMocks()。
参考 tests/__mocks__/prisma.ts 的组织方式。

Claude 增强 💡

text
读取 @src/services/payment.service.ts,
识别所有外部依赖,为每个依赖生成成功和失败两套 Mock。
参考 @tests/__mocks__/prisma.ts 的组织方式。

Claude Code 自动分析 import 链,精准区分外部依赖与内部函数。


食谱 5:回归测试补充

场景描述

修复 Bug 时,先写复现测试,再修代码。确保同一 Bug 不会二次出现。流程:红灯→绿灯→重构。

核心模板

text
为以下 Bug 编写回归测试,暂时不要修复代码。

Bug 描述:{{Bug描述}}
复现步骤:{{复现步骤}}
期望行为:{{期望行为}}
实际行为:{{实际行为}}
相关代码:{{相关文件路径}}

要求:
1. 精确复现 Bug 的触发条件
2. 断言期望的正确行为(当前应该失败)
3. 命名含 Bug 编号:it("should {{期望行为}} - regression #{{Bug编号}}")
4. 运行确认当前是红灯
5. 确认失败后告诉我,我再决定是否修复

变量说明

变量说明示例
{{Bug描述}}一句话概述"折扣 100% 时总价为 NaN"
{{复现步骤}}触发操作"创建订单,折扣设为 1.0"
{{期望行为}}正确行为"总价应为 0"
{{实际行为}}Bug 表现"总价为 NaN"
{{相关文件路径}}源文件src/services/order.service.ts
{{Bug编号}}追踪编号GH-142

好坏对比

修复这个 Bug:折扣 100% 时总价为 NaN。修完后加个测试。 — 无法确认测试真正覆盖了触发条件。

先测后修(红-绿-重构)

text
为以下 Bug 写回归测试,不要修复代码:
Bug:calculateTotal 在 discount=1.0 时返回 NaN
复现:calculateTotal({ items: [{ price: 100, qty: 1 }], discount: 1.0 })
期望:返回 0,实际:返回 NaN
写测试 → 运行确认红灯 → 报告给我

实战案例

text
为以下 Bug 编写回归测试,不要修复。

Bug:用户名含 emoji 时注册接口返回 500
复现:POST /api/auth/register
  body: { email: "test@test.com", password: "12345678", name: "张三🐱" }
期望:201 正常注册
实际:500 Internal Server Error

命名:it("should accept emoji in username - regression #GH-89")
运行确认红灯后报告给我。

Claude 增强 💡

text
读取 @src/services/order.service.ts,
这个函数在 discount=1.0 时返回 NaN。
先写回归测试复现 Bug,运行确认失败,再告诉我结果。不要修复代码。

配合 /test Skill 自动遵循先测后修流程。


食谱 6:E2E 测试脚本

场景描述

用 Playwright 或 Cypress 验证核心用户路径。E2E 测试少而精,只测最关键的 3-5 个核心流程。测试金字塔顶层:数量最少但价值最高。

核心模板

text
为以下用户流程编写 E2E 测试。

技术栈:{{E2E框架}}
测试文件:{{测试文件路径}}
基础 URL:{{baseURL}}

用户流程:{{流程名称}}
步骤:
{{详细步骤列表}}

要求:
1. 使用 Page Object 模式组织页面操作
2. 用 data-testid 定位元素,不用 CSS 选择器
3. 每步操作后断言验证状态变化
4. 合理等待(waitForSelector / waitForResponse)
5. 测试数据用 {{数据准备方式}} 准备
6. 参考 {{现有E2E测试}} 的模式

变量说明

变量说明示例
{{E2E框架}}E2E 框架Playwright / Cypress
{{测试文件路径}}测试文件位置e2e/order-flow.spec.ts
{{baseURL}}测试环境地址http://localhost:3000
{{流程名称}}用户流程名称"完整下单流程"
{{详细步骤列表}}操作步骤登录→加购→结算→支付→验证
{{数据准备方式}} / {{现有E2E测试}}数据来源与参考API seed / e2e/auth-flow.spec.ts

好坏对比

为每个页面写 E2E 测试,覆盖所有功能。 — 全覆盖导致测试缓慢且脆弱。

聚焦核心路径

text
用 Playwright 为"注册→登录→创建项目"流程写 E2E 测试。
步骤:/register 填表→/login 登录→/dashboard 新建项目→验证列表。
用 data-testid 定位,每步加断言。
测试数据用随机邮箱,afterAll 通过 API 清理。

实战案例

text
用 Playwright 为核心下单流程编写 E2E 测试。
测试文件:e2e/checkout-flow.spec.ts,参考:e2e/auth-flow.spec.ts
步骤:登录→/products 加购→验证购物车数量→/checkout 填地址→测试支付→验证 /orders/[id] 状态"已支付"
Page Object 模式、data-testid 定位、waitForURL 等待、afterAll 清理

Claude 增强 💡

text
读取 @e2e/auth-flow.spec.ts 和 @playwright.config.ts,
按相同 Page Object 模式为下单流程写 E2E 测试。
步骤:登录→加购→结算→验证订单。用 data-testid 定位,每步加断言。

组合技巧

契约先行 → 测试先行 → 实现

text
按以下顺序执行:
1. 先定义 {{模块}} 的输入输出类型(types/ 目录)
2. 基于类型契约写单元测试(食谱 1)
3. 写集成测试骨架(食谱 2),先标记 it.skip
4. 实现代码让单元测试通过
5. 移除 it.skip,让集成测试通过
6. 补充边界条件(食谱 3)
每步完成后跑测试,全绿再继续。

Bug 修复完整流程

text
修复流程:
1. 先写回归测试复现 Bug(食谱 5),确认红灯
2. 修复代码,确认回归测试变绿
3. 分析修复代码的边界条件(食谱 3),补充测试
4. 跑全量测试确认无副作用

测试补全冲刺

text
检查 src/services/ 下所有 Service 文件,
找出没有对应测试文件的模块,按被引用次数排序。
先列清单,我确认后逐个生成测试。

相关资源

面向个人开发者的 AI 辅助编程工程化方案