这算是一个不成熟的想法,想先记录下来,接受大家的检验和讨论。
故事要从我的日常说起。
自测的一天
我是一个后端开发,技术栈主要是 Spring Boot。一个典型的需求开发流程大概是这样的:
1 | 理解需求 → 编码 → 自测 → 联调 → 提测 |
每一步都还好——除了自测。
自测意味着:我需要证明这个接口在各种业务状态下行为正确。为了达到这个目标,我通常需要:
- 准备数据:手动往数据库里插各种状态的用户、订单、账户
- 部署服务:把改动部署到测试环境(或者本地跑起来)
- 构造请求:部署后在页面上一个场景一个场景地操作,模拟各种用户行为
- 验证结果:检查返回值、检查数据库落库、检查下游是否被正确调用
- 发现问题 → 修 → 重新部署 → 重新造数 → 重新验证
- 协调上下游:有些数据自己造不了,得找对应的同学帮忙——或者自己搭 Mock 服务
- 写自测文档:如果团队有这个要求——把测试场景、测试数据、测试结果整理成文档,附到需求上
这一套走下来,大半天甚至一天就过去了。而且这还没算上中途被拉去开个会、被各种消息打断的碎片化开销。
更糟糕的是:下次需求变了,这套流程从头再来一遍。
上次构造的测试数据,这次用不了——因为业务状态变化了,字段可能也调整了。上次踩过的坑、验证过的边界条件,这次全靠人脑回忆。上次写的自测文档,能找到就算运气好,找到了也不一定还能用——因为接口都改过了。
仔细想想,这一轮一轮的自测里,真正能被沉淀下来的东西几乎没有。数据被丢弃了,操作经验留在了脑子里,测试文档随着需求流转消失在流程的某个环节里。每一次自测,都像第一次一样从零开始。
能不能每次自测之后,留下的不只是一份"已通过"的结论,而是一些可以积累的东西?比如:
- 这次用过的测试数据,下次稍微改改就能复用?
- 这次验证过的场景模板,下次同类需求可以直接套用?
- 这次的验证逻辑,下次变成自动化的脚本,不需要再手动点一遍?
有时候我在想:这一步,有没有可能不再这么累?
为什么现有的方案没有解决这个问题?
你可能会说:咋不写单元测试呢?咋不用自动化测试呢?
先说清楚一个容易混淆的点:自动化测试通常是提测后的事——大概率由 QA 维护,用例要么在需求测试阶段编写,要么上线后通过录制真实流程自动生成。它验证的是"已经验收过的场景没有变坏",本质是回归。
而自测发生在提测前:需求还没被验证过,我要证明的是"我的实现是不是真的理解了需求"。这个窗口期里,自动化测试的用例根本还没建起来——等它建好,我早就该提测了。所以自动化测试解决的是回归问题,不是自测问题。
那现有的方案能解决自测问题吗?我们来逐个看一下。
单元测试(JUnit / Mockito)
单元测试很好,但它解决的是方法级别的逻辑正确性,而不是业务场景的正确性。
比如一个转账接口,单元测试能覆盖:
1 | accountService.transfer(...) → 参数校验通过 → 余额扣减成功 |
但它覆盖不了:
1 | 用户状态 = "风控冻结" |
这不是一个方法内部能验证的事情,它涉及多个服务之间的协作逻辑。
要覆盖这种场景,你需要的是集成测试。
集成测试(Testcontainers / WireMock)
集成测试能覆盖跨服务的场景,也确实有成熟的自动化实践:Testcontainers 在测试里拉起真实的数据库等依赖,WireMock 按场景模拟下游接口,契约测试把"下游别乱改"固化下来,整套可以跑在 CI 里。
但这类方案解决的主要是"运行"这一环,真正贵的地方反而没被碰到:
- 用例从哪来:覆盖哪些业务场景,还是靠人根据需求逐个设计;需求迭代几次之后,用例和业务的对应关系就开始模糊
- 数据怎么造:测试数据依然要手工构造,字段一变就要跟着维护
- Mock 怎么维护:每个人各自搭的 Mock 风格不一,下游接口一改,散落的 Mock 成片失效
- 结果怎么沉淀:测试报告和业务规则之间没有结构化的关联——覆盖了什么、为什么这么测,还是留在人脑子里
于是集成测试很容易陷入这样的处境:写了,但覆盖不全;跑了,但不敢说它真能代表业务。需求每变一次,脚本维护就重来一遍——改不动的时候,它就变成了一次性产物:写完跑一次,然后就扔了。
AI 单元测试生成
现在很多工具(Copilot、Cursor 等)已经能自动生成单元测试了。但它们生成的通常是:
1 |
|
这种测试有价值,但不高。它验证的是路径通不通,而不是业务对不对。
真正的黄金测试是那些覆盖了业务状态组合、边界条件、异常流程的测试——而这恰恰是现有 AI 工具做不到的,因为它们不理解你的业务语义。
我想尝试的方向
一句话概括:
用 AI 根据需求或代码变更生成业务场景级的集成测试用例,包括 Mock 方案,然后自动运行、生成测试报告,形成验证闭环。
具体来说,这个流程是这样的:
1 | 需求 / 代码变更 |
这里有几个关键点:
1. AI 生成的不是代码,是场景
第一步不是让 AI 写 JUnit,而是让 AI 理解需求,输出结构化的测试场景:
1 | 场景:转账接口 - 用户被风控冻结 |
业务人员能看懂、开发能对齐、AI 能据此生成代码。
2. Mock 方案是显式产出物
集成测试绕不开外部依赖。传统做法是每个开发自己搭 Mock,或者用统一的 Mock 平台。
区别在于:这里 AI 生成的 Mock 方案是结构化且可复用的。
1 | Mock:风控服务 checkRisk(userId) |
后续如果有人需要同样的 Mock 场景,直接引用这套方案,不用重新沟通、重新配置。
更进一步:这些 Mock 方案可以作为契约给到下游接口提供方——“我们测试时需要的下游接口返回格式是这样的,你们改接口的时候注意别破坏这些场景。”
3. 测试报告是闭环的起点,不是终点
测试跑完之后不只是"过了"或者"没过"。测试报告包含了:
- 哪些场景通过了
- 哪些场景失败了,失败在哪一步
- 失败的原因(代码 bug?还是 Mock 数据过期?)
然后 AI 可以根据报告定位问题、修复代码、重新运行,直到全部通过。这和 AI Agent 的"执行-反馈-修正"循环是一致的。
一个具体的推演
假设你正在开发一个转账接口,需求文档说:
用户 A 向用户 B 转账,扣除 A 的余额,增加 B 的余额。如果 A 被风控冻结,拒绝转账。如果余额不足,拒绝转账。如果下游渠道返回超时,走降级重试逻辑。
AI 看了这段需求,生成以下测试场景:
| # | 场景 | Mock 策略 |
|---|---|---|
| 1 | 正常转账成功 | 风控返回正常,余额充足 |
| 2 | 风控冻结拒绝 | Mock 风控返回冻结 |
| 3 | 余额不足拒绝 | Mock 风控返回正常,A 余额设为 0 |
| 4 | 渠道超时重试 | Mock 渠道前 3 次超时,第 4 次成功(次数取决于实际重试配置,此处仅为示例) |
| 5 | 渠道最终失败降级 | Mock 渠道 4 次全部超时 |
| 6 | 幂等重放保护 | 同样参数调用 2 次,第二次不重复扣款 |
AI 为每个场景生成对应的 Mock 数据和集成测试代码。跑完之后,测试报告显示:
1 | ✅ 1. 正常转账成功 — 通过 |
你不需要手动去分析哪个场景出问题——测试报告定位了根因,你直接看是代码问题还是 Mock 数据配置问题。
这就是我想要的:不是让 AI 替我做某一步,而是让 AI 帮我串起整条链。
更深一层:测试不只是为了"过"
如果这个想法只是为了"少测几次",那它的价值天花板很低。但它不是。从下面三个视角来看,一套持续维护的业务场景测试,价值远超自测本身。
视角一:测试是 AI 理解代码的"参考答案"
现在的 AI 编程工具,最大的局限不是生成能力,而是理解能力。
AI 看一段代码,如果没有任何行为锚点,它只能看到语法——“这里有一个 if 判断,那里有一个 try-catch”。但它不知道:
- 这个 if 判断的业务含义是什么(为什么冻结用户就不能转账?)
- 这个 try-catch 的容错策略是什么(重试几次?降级到哪里?)
- 这个字段为什么是这个类型(Long 而不是 Integer?)
而一套覆盖业务场景的集成测试,天然地告诉了 AI:
1 | Given 用户状态 = "冻结" |
这就是可执行的业务规范(与《Specification——把决策翻译给 AI》里"把决策翻译给 AI"的思路一脉相承)。代码本身是 What 和 How,测试描述的是 Why 和 When。
以后 AI Agent 要修改这个模块的代码时,它不只需要看懂代码,还需要理解业务规则。而测试用例——如果足够丰富——就是它理解业务规则的最好入口。
视角二:测试是团队的"活文档"
“活文档”(Living Documentation)不是新概念——用可执行的测试来描述系统行为。但当测试需要人工编写和维护时,文档和代码的同步本身就是一项负担。
AI 生成的集成测试改变了这个等式:场景用例由需求驱动自动生成,需求变 → 场景变 → 测试变,维护成本从"人追着代码改"变成了"AI 追着需求改"。活文档终于有可能"活"起来,而不是写完就过期。
视角三:测试数据的长期价值
开头说的自测困境里,最可惜的就是测试数据——每次造完、用完、就被扔掉。如果这套流程能让测试数据沉淀下来,并不断吸收测试环境里真实业务流产生的数据、生成更接近真实分布的测试数据,那当它积累到一定规模后,会成为:
- 性能基线的参考:同一批数据,新版和旧版的耗时对比
- 回归的标尺:新功能上线后,这批数据的行为是否一致
- 容量规划的输入:真实分布的数据,跑出来的 QPS 才有参考意义
这已经超出了自测的范畴,进入可观测性和容量工程的领域。
必须正视的问题
想法再好,也得面对现实。有几个我还没想清楚的问题:
1. 测试腐化怎么控制?
AI 生成测试很快,但业务也在快速迭代。今天生成的测试,下周接口逻辑改了,测试可能变成绿色噪声——跑过了,但什么也没验证。
需要一种机制来追踪"哪些测试覆盖了哪些代码路径",代码变更后,AI 主动标记可能失效的测试。
2. Mock 和真实环境的差距怎么弥补?
Mock 的数据是我们设定的理想情况。但下游接口的真实返回可能:
- 字段多了、少了
- 返回码的语义变了
- 响应时间不符合预期
这会导致测试全绿、上线全红。
可能需要定期从真实环境抽样,对比 Mock 数据是否还匹配真实返回。
3. Spring Boot 测试启动慢,怎么保证闭环速度?
一个中等规模的 Spring Boot 应用,@SpringBootTest 启动一次 30-60 秒(本地开发机上的大致量级)。如果测试场景有几十个,跑一轮可能要十几分钟。
这会让"生成 → 运行 → 反馈 → 修改"的闭环变得很慢,体验极差。
可能的缓解手段:按模块拆分 context、Test Slice、增量运行、context 缓存——但都需要纳入早期设计。
这里有两项值得优先考虑:
Test Slice:不是每个测试都需要完整应用上下文。@WebMvcTest 只加载 Controller 层,@DataJpaTest 只加载持久层——启动时间从 30 秒降到 3-5 秒是常见的。对 AI 生成的集成测试来说,场景描述里明确了"关注哪些层",AI 完全可以据此选择合适的 Slice 注解——而不需要人来判断。
Context 缓存:Spring TestContext 框架本身会按配置缓存上下文。但如果不同测试用了不同的 @MockBean、不同的 profile、不同的 properties,缓存就会被碎片化——每个组合都要单独启动一次。这要求生成测试时尽量收敛配置差异,或者接受首轮冷启动的代价、用增量运行抵消后续轮次的开销。
4. 小项目和大项目的 ROI 边界在哪里?
一个简单的 CRUD 项目,业务逻辑就是增删改查——搞这套纯属浪费。
一个复杂的金融/电商/供应链系统,跨服务的协作逻辑极多——搞这套物超所值。
中间地带怎么判断?需要一个大致的 ROI 评估框架。
5. 和现有测试体系的关系怎么界定?
大多数团队已经有单元测试、DAO 层测试、甚至部分手工测试用例。这套东西加进来,定位不清晰就会出现"到底信哪个"的混乱。
我目前的设想:
1 | 单元测试 → 验证方法级逻辑正确性 |
各有分工,互补而非替代。
和 QA 的自动化测试也要划清边界:自动化测试跑在提测后、由 QA 维护,负责回归;这套跑在提测前、服务于开发自测,负责验证需求理解。自测沉淀下来的场景用例,反而是 QA 自动化用例的现成输入。
这不是一个工具,而是一个方向
写到这里,我想澄清一点:我不是在描述一个"自动生成 JUnit 的插件"——那个已经有人在做了,效果也有限。
我在想的是:
让 AI 深度参与软件验证的全过程——从场景设计到数据构造,从运行验证到报告分析,从问题定位到回归验证。让测试代码成为业务知识的载体,让验证闭环成为 AI 理解系统的桥梁。
这是一个方向,不是一个产品。
请你来拍砖
以上就是一个后端开发在自测困境里的一些碎碎念。
这想法还有很多不成熟的地方。技术可行性、工程落地、ROI 边界——每个维度上都还有大量没想清楚的问题。
正因为如此,才想把它写出来,接受大家的检验。我打算下一步找一个规模合适的项目,把这条闭环最小化地跑一遍,验证"生成 → 运行 → 修复"的节奏到底能不能接受——哪些环节真的可行、哪些只是空想,到时候再回来汇报。
如果你有相关的实践经验、碰到过类似的坑,或者觉得这个方向根本不靠谱——都欢迎讨论,讨论就是价值。