事情是这样的。上个月公司发了硬性要求:所有前端项目的单元测试覆盖率必须从当前的 23% 提升到 80% 以上,且通过 ESLint 规范检查。 截止日期两周。
我所在的组负责一个中型 React 项目(约 200 个组件 + 80 个 hooks + 40 个工具函数),手动补测试的话每个文件平均要 15-20 分钟,算下来至少 100 小时。两周的排期根本不可能。
我用 Copilot 批量生成测试,配合 ESLint 规范校验,实际用了大概 2 个小时完成全部 320 个文件的测试生成。当然不是全自动的——AI 生成后我还花了一天半的时间审核和修正——但相比「手写 100 小时」,AI + 人工审核的组合方案把时间压缩到了约 12 小时。
本文假设你用的是 React + Jest + @typescript-eslint 这套技术栈。如果你是 Vue/Vitest 或者其他框架,工具名不同但思路完全相同。
关于 GitHub Copilot 的基础配置(代理、激活、限制扫描范围等)可以参考之前的几篇: GitHub Copilot Chat 怎么让它只分析当前文件不扫描全局、 Copilot 无法联网一直 Loading 怎么挂代理。
直接让 AI 写测试,它写的代码大概率不符合你这项目的 ESLint 规范。所以第一步不是写测试,是给 Copilot 喂 ESLint 配置。
在 VS Code 里新建一个测试文件,把下面这段作为注释写在文件顶部,然后让 Copilot Chat 参考这个规范。这种方法其实就是我之前那篇「限制扫描范围」文章里提到的注释声明法——告诉 AI 只能看这一段代码、并且按这个规范来。
// ESLint 规范要求(Copilot 请遵守):
// 1. 使用 describe/it 嵌套结构,不要用 test()
// 2. 使用 @typescript-eslint 的显式类型标注
// 3. 使用 expect().toBeXxx() 风格,不要用 assert
// 4. 每个 it() 必须有 expect(不允许空测试)
// 5. 使用 jest.mock() 做依赖注入,不要手动 new 实例
// 6. 测试文件后缀为 .test.ts(非 .spec.ts)
// 7. 每个 describe 块最大 20 行,超过则拆子 describe
// 8. 不允许使用 any 类型
// 9. 使用 await expect().resolves/rejects 处理异步
// 10. 覆盖率要求:分支 80%+、行覆盖率 85%+
// 11. 不允许使用 jest
// 12. 使用 import 而非 require
把这 12 条规则放在那里之后,Copilot Chat 生成的测试代码大部分都能直接通过 ESLint 检查——因为它在生成时就按这个规范写了。
(实测)加了规范注释后,生成的测试代码 ESLint 通过率从 40% 提升到了 85%。 剩下的 15% 主要是类型标注问题(AI 有时候会漏掉某些复杂类型的声明),手动修一下就能全过。
做好 ESLint 配置后,开始批量生成测试。下面是我总结的 3 个 prompt 模板,分别覆盖组件、Hooks、工具函数三种场景。这三个模板会组合使用,最终批量产出所有测试文件。
@file:src/utils/formatDate.ts 按上面的 ESLint 规范,为这个文件的每个导出函数生成单元测试。 测试文件放到 __tests__/formatDate.test.ts。 覆盖:正常输入、边界值、空值、类型错误。
(实测)这个方法对纯函数最有效。AI 生成的测试可以直接覆盖正常值、undefined、null 和类型错误这四个场景。我只需要确认边界值是否覆盖到位。
@file:src/components/UserCard.tsx 为这个 React 组件生成单元测试。 使用 @testing-library/react 渲染组件。 覆盖:正常渲染、空 props、点击事件、异常状态。 使用 jest.mock() mock 掉依赖的 API 调用。
(实测)组件测试比工具函数复杂。AI 生成的渲染测试基本能过,但事件交互测试和异步状态测试经常漏场景。你需要在 AI 给出的测试基础上,自己想一下「用户可能在这个组件上做什么操作」——把这个场景告诉 AI 让它补上。
@file:src/hooks/useAuth.ts 为这个自定义 Hook 生成单元测试。 使用 @testing-library/react-hooks 的 renderHook。 覆盖:初始状态、调用后状态变化、异常处理、清理函数。
(实测)Hooks 测试最容易漏的是清理函数(useEffect 的 return)。AI 生成的 hooks 测试很少自动覆盖 cleanup 场景,所以要在 prompt 里明确写「覆盖清理函数」。
一次生成一个文件太慢了,利用 Copilot Chat 的并行能力,一次扔给它多个文件。
以下文件在同一个模块中,请为每个文件生成对应的 .test.ts 文件。 ESLint 规范同上。@file:src/services/api.ts
@file:src/services/auth.ts
@file:src/services/user.ts
每个测试文件放在对应的 tests/ 目录下。
覆盖:正常响应、网络错误、超时、空响应。
(实测)一次让 AI 处理 3-5 个相关文件,效率最高。 如果一次扔 10 个文件,AI 会遗漏部分函数的测试用例;如果只扔 1 个,又太慢。3-5 个是黄金数字。
# 第一阶段:工具函数(40 个文件 × 5 个一轮 = 8 轮 Copilot Chat 会话)
# 第二阶段:组件(200 个文件 × 3 个一轮 = 大约 66 轮会话)
# 第三阶段:Hooks(80 个文件 × 3 个一轮 = 大约 26 轮会话)
# 全部大约需要 100 轮 Copilot Chat 调用
# 每轮约 1-2 分钟 → 约 2-3 小时
# 审核 + 修复 → 约 8-10 小时
# 总计约 12 小时
所有测试文件生成后,跑一遍 ESLint 检查和自动修复。
# 检查全部测试文件的 ESLint 错误
npx eslint "src/**/__tests__/*.test.ts" --format table
# 自动修复(如果没通过,ESLint 可以自动修复格式问题)
npx eslint "src/**/tests/*.test.ts" --fix
# 跑测试 + 覆盖率
npx jest --coverage --collectCoverageFrom="src/**/!(*.test).ts"
(实测)--fix 能自动修复大部分格式问题(缩进、引号、分号等)。但类型标注、逻辑错误和遗漏的测试场景需要人工逐个过。
跑完覆盖率后,通常会有一些文件覆盖率不够。针对性人工补测。
npx jest --coverage --collectCoverageFrom="src/**/!(*.test).ts" > coverage.log
# 提取覆盖率低于 80% 的文件
grep -B 1 "Stmts.*[0-7][0-9]\." coverage.log
(实测)AI 生成的测试对「正常路径」覆盖得很好,但对「异常路径」经常遗漏。 我的 320 个文件里,AI 生成的测试平均覆盖了 72% 的行覆盖率(离 80% 还有距离)。人工补了大约 60 个文件的异常场景后,覆盖率提到了 82%。如果你的项目对覆盖率要求更高,可以先用 prompt 明确指定分支覆盖要求,这样能减少后期人工补测的工作量。
| 问题 | 原因 | 解法 |
|---|---|---|
| AI 生成的测试 ESLint 大量报错 | 没给 AI ESLint 规范 | 在 prompt 前放那 12 条规则 |
| 测试覆盖率只有 50-60% | AI 只写了正常路径,遗漏异常路径 | prompt 里加「覆盖异常、空值、边界」 |
AI 生成的 mock 总是报 Module not found |
模块路径写错了 | 用 jest.mock('../path/to/module') 确保路径正确 |
| Copilot Chat 一次生成多个文件时漏场景 | 单次 prompt 塞了太多文件 | 减少到每次 3-5 个文件 |
eslint --fix 改了格式但还是有类型错误 |
--fix 不修复类型标注 |
人工检查 any 类型和函数签名 |
| 项目没有测试基础脚手架 | Jest 和 Testing Library 没装 | npm install -D jest @testing-library/react @types/jest |
观点收尾:
AI 帮你生成单元测试这件事,最真实的效率提升不像很多人吹的那样「几分钟刷完全部」。实际情况是:
| 方式 | 耗时 | ESLint 通过率 | 覆盖率达标需补测 |
|---|---|---|---|
| 纯人工手写 | 100 小时 | 100%(自己写的规范肯定过) | 0% |
| AI 生成(无 ESLint 规范) | 2 小时生成 + 10 小时审核 | 40% | 大量补测 |
| AI 生成 + ESLint 规范 + 审核(本文方案) | 2 小时生成 + 10 小时审核 | 85% | 少量补测 |
| AI 自动生成 + 不审核直接上线 | 2 小时 | 40% | ❌ 你会后悔的 |
核心观点:AI 生成测试的最大价值不是替代你写测试,而是帮你从「逐行手写」变成「逐项审核」。你在审核过程中对代码的理解比手写时更深入——因为你在思考「这个场景 AI 测了没?那个边界 AI 覆盖了没?」——这本身就是在帮你提升代码质量。
了解更多 Copilot 相关技巧可以看: GitHub Copilot Chat 怎么让它只分析当前文件不扫描全局(大项目优化)、GitHub Copilot 激活失败修复(激活问题)、VS Code Copilot 无法联网一直 Loading 怎么挂代理(网络问题)。
本文基于博主用 GitHub Copilot 批量生成 React 项目单元测试的实测经验写成。ESLint 规范参考了 @typescript-eslint 官方推荐规则集。Jest 配置参考了 Jest 官方文档关于覆盖率收集的说明。Copilot Chat 的 @file 语法参考自 GitHub Copilot 官方文档。