在耦合深、逻辑杂、文档少的老旧系统中,如何安全地向前走?我们用 Vitest + AI 辅助生成测试用例,构建了一套"以测试用例为验收标准"的迭代模式。

一、背景与困境
我们负责的业务模块是一个服役超过N年的前端系统,技术栈为 Vue3 + TypeScript。随着业务快速演进,代码逐渐暴露出典型的老旧系统特征:
- 组件耦合深:父子组件通过多层 props 传递状态,兄弟组件共享全局 Store,改动一个组件往往"牵一发动全身"
- 业务逻辑分散:部分逻辑在组件生命周期中,部分在自定义 Hook 中,还有一部分藏在工具函数里
- 测试覆盖率近乎为零 :历史迭代追求速度,几乎没有单元测试,回归完全依赖人工 - 国内有一段时间是在推崇写
单元测试,但是薪资待遇没变, 事变多了, 工时没有增加, 基本很多团队是不太愿意做这个事情了。 - 文档缺失:业务规则只存在于少数核心开发者的记忆中
- 测试用例不全: 人员变动, 测试用例可能只有某几次的版本,导致改动影响很困难。
每次需求迭代,开发人员都如履薄冰------改一行代码,不确定会影响到哪里。
调试时间长, 测试范围模糊,不确定。
目前有遇到 嵌套 7-8层的 组件, 还有 组件之间各种传递大对象(50+字段)以上的。 调试的时候数据源复杂, 场景多变, 多个人员迭代, 参数传递越来越多, 实在是迭代不动。
单个模块代码爆炸 3000+ 行的逻辑。
二、破局思路:以测试用例驱动开发
我们引入的核心思想是:在修改业务代码之前,先为现有行为编写测试用例,让测试用例成为"安全网"和"行为说明书"。
有一些功能, 是人工就明显可以判别的 , 可以作为 背景梳理出来。 其他的已经是代码中存在的, 但是没有注释, 功能耦合严重的, 就依赖AI梳理。
具体工作流如下:
markdown
1. 确定要修改的业务范围(某个组件 / 某个 Hook / 某个工具函数)
2. 将当前代码 + 相关依赖(props、store、外部接口)交给 AI
3. AI 辅助生成该模块的单元测试用例(Vitest)
4. 运行测试 ------ 此时测试应该全部通过(绿色)
5. 开始修改业务逻辑
6. 再次运行测试 ------ 如果变红,说明改动影响了预期行为,需要排查
7. 所有测试变绿后,提交代码
这个模式的核心价值在于:测试用例不是事后补充,而是事前锁定的"行为基线" 。
三、技术选型:Vitest
我们选择 Vitest 作为测试框架,原因如下:
| 特性 | 优势 |
|---|---|
| 与 Vite 生态无缝集成 | 项目已使用 Vite 构建,零配置成本 |
| 极快的执行速度 | 采用原生 ESM 和 SWC,测试反馈即时 |
| Jest 兼容 API | 学习成本低,describe / it / expect 语法通用 |
| 强大的 Mock 能力 | vi.mock 轻松隔离外部依赖 |
四、AI 在流程中的角色:测试用例生成器
我们并没有让 AI 直接修改业务代码,而是将 AI 定位为 "测试用例辅助生成工具" 。
以某一个组件(最小单元) 为例, 将 某个组件要的 输入都 整理出来, 给 到AI, 提示词就是
补充 xx 文件的 vitest测试用例, 根据我提供的测试数据, 如果场景是一致的, 列举一种场景即可。
前提是 vitest 都配置好了。 这个也比较简单。
特别是 某一个组件, 在多个入口场景被使用, 那么 就应该 明确列举一下
注意::大模型是有上下文限制的, 不要一次对多个模块补充测试用例, 最小单元去做测试用例补全。
- 模块1-xx入口; props 入参数据
- 模块2-xx入口; props 入参数据
- 模块3-xx入口; props 入参数据
...


AI 生成测试用例的效果
| 维度 | 效果 |
|---|---|
| 覆盖度 | 覆盖正常路径、边界条件、异常情况 |
| 效率 | 从手动编写 30 分钟 → AI 生成 + 人工修正 5 分钟 |
| 质量 | 需人工校验边界条件和业务规则是否准确,AI 可能遗漏隐性规则 |
| 可读性 | 测试用例本身成为了"可执行的文档" |
五、测试用例如何帮助我们安全迭代
场景一:重构组件内部逻辑
我们要将 OrderCard 中的状态判断逻辑抽取到一个自定义 Hook useOrderStatus 中。
- 修改前:运行测试 → 全绿 ✅
- 修改后:运行测试 → 如果变红 🔴,说明抽取逻辑时遗漏了某个分支条件
- 修复:对比测试预期,补全逻辑,直到全绿
场景二:修改公共工具函数
formatPrice 原本只支持两位小数,新需求要支持三位小数。
- 修改
formatPrice后,所有依赖它的组件测试都会运行 - 如果某个组件测试变红,说明该组件对金额格式有隐性依赖(比如只取两位显示)
- 这提醒我们:要么修改组件适配新格式,要么在工具函数中做兼容处理
场景三:依赖升级或 API 变更
后端接口字段从 order_status 改为 status。
- 修改数据映射层后,跑一遍全量测试
- 变红的测试精准指出哪些组件还在使用旧字段名
- 相比人工排查,节省数小时
六、落地过程中的挑战与应对
| 挑战 | 应对策略 |
|---|---|
| 组件依赖过深,难以单独测试 | 使用 vi.mock 模拟子组件和 Store,聚焦当前单元 |
| AI 生成的测试用例有误 | 人工 Review 并修正,逐步沉淀测试模板 |
| 测试环境与真实环境差异 | 补充集成测试,但单元测试仍作为第一道防线 |
| 团队不熟悉测试编写 | AI 辅助降低门槛,但要求团队理解测试意图,而非盲目信任 |
| 测试执行时间变长 | Vitest 的 watch 模式 + 只运行变更相关测试,保持反馈速度 |
小结
越是老旧系统, 人工维护的成本和精力越大。 在借助AI的帮助下, 思考这种场景如何破局。 从一上来先改代码的思维 变成 先补业务场景的边界, 再基于边界决定如何修改
我们后面对于复杂业务场景, 可能有2种比较好的选择
- 基于当前的测试用例,打补丁,测试用例边界已经梳理清楚 (
好迭代的场景,或者打补丁的代价和代码的复杂度不大), 可直接 给AI 投喂准确的需求, 迭代 - AI 结合测试用例,发现这个
模块(方法, 组件,接口) 不适用了, 直接将某个模块可以 copy一份, 将不要的逻辑删除, 再进行迭代,可能开发成本+测试成本更低,影响范围更小。
系统越是庞大, 越是老旧, 越是依赖人口口相传的地方, 基于这套方式的实践,在下一次迭代的意义越是明显。