站内精选

一句话结论

用 Cursor 加 Claude 给老项目三个核心函数补测试,半小时左右能拿到可跑用例和覆盖报告,前提是先让 AI 读完调用链。

这篇解决什么问题

接手一个跑了三四年的服务,谁都怕动它。没有测试兜底,改一行代码就得人肉回归,所以第一步往往是把最关键的几个函数先测起来。

这篇讲的就是这件事:不重构、不追求全覆盖,只圈出三个核心函数,用 AI 补上第一批能跑的单测,顺手产出一份能提交的覆盖报告。

适用:代码能本地跑起来、但单测基本为空的老项目。不适用:编译或启动都过不了的项目,那种得先解决可运行性。

开始前要准备什么

  • Cursor:免费额度跑这活基本够,重度使用需订阅
  • Claude 或 DeepSeek 任选一个,用来做第二意见
  • 项目能本地编译,测试框架和覆盖率插件已配好
  • 三个核心函数的类名方法名,最好带一句改动频率
  • 时间预留:三个函数半小时到一小时

我自己的组合是 Cursor 主编、Claude 复核。DeepSeek 慢一点,但在解释报错和写中文注释上更耐心。工具其实不用纠结,顺序比工具重要。

具体怎么做

第 1 步 · 让 AI 先读调用链

老项目写测试最费时间的不是写断言,是搞清楚这个函数到底碰了哪些外部东西。跳过这步直接让它写,它只会照函数签名猜 mock,跑起来十个错八个。

你是资深 Java 工程师,帮我梳理一段存量代码的调用关系,这一轮只读代码,不要改任何文件。
项目根目录:legacy-order-svc
目标函数:com.demo.order.PriceService 下的 calcDiscount、splitOrder、calcFreight
请按以下顺序输出:
1. 每个函数分别被哪些类调用,只写类名和方法名;
2. 每个函数内部调用了哪些外部依赖,分类标出:数据库、RPC、缓存、静态工具类、配置中心;
3. 逐个标注这些依赖在单元测试里必须 mock,还是可以直接构造真实对象;
4. 找出隐式输入:配置文件读取、System.currentTimeMillis、Random、ThreadLocal、静态可变字段。
最后给一句判断:这三个函数里,哪个的测试成本最高,为什么。不要写测试代码。

预期产出:一张依赖清单,标清哪些必须 mock、哪些能直接 new。这份清单是后面所有用例的地基。

第 2 步 · 定优先级和边界

三个函数不能平均用力。改动频繁、出错后果重的那个先测,剩下的排后面,这个判断让 AI 给理由,我再砍。

基于上一步的调用链结论,为 calcDiscount、splitOrder、calcFreight 各列一份边界条件清单。
要求:
– 每个函数给 5 到 8 条边界,必须覆盖 null 和空集合、金额为 0 或负、阈值临界值、重复调用、依赖抛异常这五类;
– 每条边界后面加一句话,说明它防的是什么线上问题,不要写「覆盖分支」这种空话;
– 按「改动频率乘以出错后果」给三个函数排优先级,写出排序理由;
– 明确列出这轮不测的分支,并说明原因,我要的是取舍不是全覆盖。
用表格输出,不要写测试代码。

预期产出:一份优先级排序加边界清单,通常能筛掉一半不值得测的场景,省下的时间比生成用例更多。

第 3 步 · 一次只生成一个函数的用例

我试过让它一口气写完三个函数,结果是三种风格混在一个文件里。改成一轮一个函数,跑通再下一个,返工量差很多。

现在开始写单元测试,本轮只写 calcDiscount 一个函数。
目标文件:src/test/java/com/demo/order/PriceServiceTest.java
约束:
– 框架用 JUnit 5 加 Mockito,断言用 AssertJ;
– 方法名统一 should_预期结果_when_场景 格式;
– 一条用例只断言一件事,禁止一个方法测五个分支;
– mock 只打桩当前用例用到的依赖,不要用 @Mock 全局铺开;
– 被测对象直接 new,不走 Spring 容器;
– 每条用例上方加一行中文注释,写清楚它在防哪种回归。
写完先不要解释,等我跑完反馈。

预期产出:一个能直接放进 test 目录的测试类。跑之前先扫一眼断言,尤其是金额和舍入相关的期望值。

第 4 步 · 跑挂了再回头问

第一轮基本都会挂,这不是失败,是暴露问题。关键是别顺手改断言让它变绿,那样等于给自己盖了个假章。

测试跑完了,下面是报错栈,逐条给我判断。
[粘贴报错栈]
要求:
– 先区分是「测试写错了」还是「被测代码本身有缺陷」,不要默认是测试的问题;
– 如果是 mock 打桩不对,指出具体哪一行、应该改成什么;
– 如果暴露出业务代码的隐藏问题,单独列出来,标风险等级,并说明它现在为什么没被线上发现;
– 严禁通过修改断言期望值来让测试通过,需要调整预期必须先说明业务上正确的值是多少。

预期产出:一份归因清单。我在实操中发现,这一步经常能挖出存量代码里一两个从没被触发过的空指针分支。

第 5 步 · 把覆盖报告读成人话

覆盖率跑出来只是数字,真正要交的是「哪些分支守住了、哪些故意没守」。这一步让 AI 替你写结论段。

下面是 JaCoCo 的统计结果,帮我读懂它并给出下一步动作。
[粘贴各函数的行覆盖、分支覆盖数字]
请输出四部分:
1. 每个函数里未被覆盖的分支分别是什么,逐条对应到代码位置;
2. 每处未覆盖分支做判断:属于防御性代码,还是真的漏了业务场景;
3. 按投入产出比排出下一轮优先补的 3 到 5 条用例,各自大概能提升多少;
4. 写一段给团队看的结论:这轮补测解决了什么风险,还剩什么没覆盖,不要用覆盖率数字当结论。
语气按技术文档来,不要写鼓励的话。

预期产出:一段可以直接贴进 PR 描述或周报的结论,加上下一轮的补测清单。

实测记录

环节 实际情况
存量代码规模 三个函数约 400 行,分散在 2 个类里
调用链梳理 约 5 分钟,AI 找出 2 个我漏掉的静态依赖
写用例并跑通 单函数约 10 分钟,三个函数半小时左右
覆盖率变化 行覆盖从 0 到 60%~85%,分支覆盖 50% 上下
返工情况 首轮 mock 打桩错 2 处,改了 1 次全绿
与手工对比 这三个函数我自己写,估计 2 小时起步

成本上,整轮下来只消耗了少量模型额度,没有额外支出。省下来的主要是「翻代码找依赖」那段时间,写断言本身并没快多少。

最容易错的 3 个地方

  1. 一口气让 AI 写三个函数,用例风格混乱、断言互相污染。改成一次只做一个。
  2. 没读调用链就开写,mock 全靠猜,跑十个错八个。顺序不能反。
  3. 报错就顺手改断言让它变绿。先判断是测试错还是代码有 bug,后者要单独记。

第三条是我踩得最狠的。当时有个折扣计算一直挂,我让它把期望值调了一下就绿了,后来才发现是业务代码在多币种场景下少了一次换算。

可复用的东西

五段提示词其实是一条流水线:读调用链、定边界、单函数生成、报错归因、覆盖报告解读。前两段是判断,后三段是执行,顺序别打乱,跳过任何一段都会在后面加倍还回来。

要复用时只改三处:项目路径、函数名、测试框架。其余约束——一次一个函数、不许改断言、区分测试错还是代码错——建议原样保留,这几条是踩过坑才加上的。

补测试这件事,价值不在那几十行代码,而在那份「哪些依赖必须 mock」的清单,下次接新模块能直接拿出来用。你手上那个老项目,最先想补测试的是哪个函数?

常见问题解答

三个核心函数怎么挑,有没有客观标准?

按改动频率、出错后果、被调用次数三个维度排。改动频繁又牵涉金额或权限的先测,代码最长但半年没动过的可以往后放,长度不等于风险。

AI 生成的测试用例能直接提交吗?

能跑通之后还要人工过一遍断言,特别是金额、时间、舍入相关的期望值。凡是为了让测试变绿而调整预期的地方,必须回到业务上确认正确值再说。

覆盖率补到多少算合适?

核心函数行覆盖 60%~85% 通常够用,分支覆盖 50% 上下也算合理。与其追总量数字,不如把关键分支和异常路径守住,报告里写清楚哪些是有意不测的。

小程序阅读免费
微信扫码进入小程序,按岗位找 AI 实操步骤
微信扫码进小程序
按岗位找 AI 实操步骤 · 提示词可收藏

发表回复

后才能评论