测试,测试,还是测试

💡 在 Agent 时代,错误被更快地产出和扩散。传统的测试流程已无法满足开发速度的需求。本文提出四类测试策略——单元、接口、冒烟、E2E——并详解它们在 Agent 工作流中的最佳介入时机,帮助开发者在效率与质量间找到平衡。

Agent 现在把产出代码这一步做得非常快捷,但它也把另一件事成倍放大了:错误会被更快地产生,也会被更快地扩散。以前我一个人一天改三处逻辑,现在一个 Agent 几分钟就搞定了。以前 bug 更像是一个函数写扯了,现在这个 agent 可能搞出来的是:

• 函数本身没错,但接口契约改了 • 本地能跑,合到分支上就挂了 • 单个功能能通,但一进 release 就把别的链路搞死

所以现在测试环境不能被定义成开发后面的一个流程,而应该是 Agent 开发编排的一部分。这篇文章我就想分享我现在是怎么做的。

四类测试的使用

我现在主要定义的测试就是单元测试,接口测试,冒烟测试和 E2E 测试。而且这几种不同层级的测试需要在不同的时候来运行和验证,否则就会拖延开发的效率。单元测试是在拦低级错误,接口测试是在拦协作错误,冒烟测试是在拦集成事故,E2E 测试是在拦截用户体验事故。

测试层次 它真正回答的问题 如果缺失,会发生什么
单元测试 这次局部改动有没有把最基础的逻辑写坏? bug 在最便宜的时候没被拦住
接口测试 模块之间还能不能按约定协作? 功能单点都对,但拼起来坏
冒烟测试 这次改动合进来后,核心流程还活着吗? 看起来能 merge,实际一发就炸
E2E 测试 用户从头到尾跑一遍,系统体验是否仍然成立? 工程链路正常,但用户路径断了

四类测试的介入时机

测试类型 最适合的介入时机 主要目标 最忌讳的误用
单元测试 Agent 每次完成一个局部函数/模块改动后立刻跑 快速拦住局部逻辑错误 拿它验证整条业务链路
接口测试 一个功能块完成、准备提交 feature 分支前 验证模块契约、输入输出、依赖协作 全靠 mock,测成假接口测试
冒烟测试 PR 准备合并、或合并到 release 分支后立刻跑 确认核心路径还活着 一次塞太多场景,跑成小型 E2E
E2E 测试 release 候选版本、关键上线前 验证真实用户主路径 把它当日常开发内环主力

越靠前的测试,应该越快、越窄、越便宜;越靠后的测试,应该越少、越重、越贴近真实环境。

单元测试应该什么时候跑?

单元测试不是发版前跑的,它应该是 Agent 开发内环的一部分。

只要 Agent 做的是下面这类局部,确定,反馈便宜的事情,单元测试就应该尽量立刻跑:

• 改纯函数 • 改规则判断 • 改状态转换 • 改 schema 映射 • 改数据清洗逻辑 • 改工具参数拼装 • 改 import / export 的字段处理

在我的 Agent workflow 里,单元测试挂在两个点:Agent 每完成一个局部实现后自动跑一次,以及 Agent 准备结束本轮修改前再聚合跑一次相关 test。这层测试要快,所以最适合让 Agent 自动添加单元测试,并且在改完局部逻辑后自动触发,每次小的功能点改动后 commit,并且增加 pre-commit hook 自动跑相关测试文件。

改动类型 单元测试时机
新增纯函数 写完立刻跑
修改已有规则判断 修改后立刻跑相关 case
修复 bug 先补回归测试,再让 Agent 改代码,再跑
重构实现但不改行为 改完立刻跑

接口测试应该什么时候跑?

因为上下文有限导致记忆不准,或者有多个 agents 在同步修改的场景下,经常会出现以下问题:

• 参数名改了,调用方还在用旧字段 • 返回结构变了,下游 parser 没跟着改 • 工具调用顺序看似没问题,但状态语义已经完全不同了 • 数据库写入成功了,但 API response contract 变了 • 一个模块加了默认值,另一个模块因此误判成功

所以在一个 feature 的局部实现已经完成,准备提交 feature 分支、或者准备开 PR 之前需要进行完整的接口测试。

我主要的接口测试包含:

• 前后端 API contract • tool call 输入输出 contract • 数据库读写边界 • webhook/event payload • 文件导入导出结构 • prompt output schema • agent step 之间的状态传递格式

接口测试通常比单元测试慢一点,但还没非要等 CI 的时候做。所以我会优先放在:Agent 自测 feature 完成后,让它补全所有的接口测试代码,并且验证。在 pre-push 之前用 hook 来触发跑一轮,最好在 PR 创建前再跑一轮。

冒烟测试应该什么时候跑?

冒烟测试验证这次改动进了集成态之后,核心流程有没有挂掉。因为我自己会把控 worktree 的测试,所以冒烟测试只在两个流程做,一个是 PR 合并这个 worktree 之前,还有就是合并到测试 release 的版本之前。

冒烟测试基本上就只做以下几个:

• 应用能启动 • 核心页面能打开,并且返回数据 • 关键 API 返回正常 • 主路径 1~2 条能跑通 • 关键依赖(DB / cache / queue / model service)没断

有一个注意的点就是别把它写成一个缩小版 E2E 大全。这一层不要追求全面,只追求关键路径活着,我会把它定义在 CI 中,每次 PR 或者 merge 的时候运行,以及每次做 release 的时候。

E2E 测试应该什么时候跑?

E2E 测试最贵,但是也是很重要的守护一环。但是它不应该成为 Agent 日常开发内环的主力。最适合的时机通常是合并到 release 版本之后,而且要记录经常改错的,高风险的主路径,尤其是核心功能模块可能经常涉及到改动。

E2E 最应该做的验证是用户的使用路径成立,保证业务路径从头到尾是否还通畅和成立。我现在的处理方式就是在 CI 中增加夜间定时任务跑更完整的 E2E 套件。高风险改动才临时加跑本地。

我现在的流程:从 feature issue 到 release,应该过哪些测试?

根据我自己的开发节奏,现在是这样设计的:

阶段 目标 应该过的测试
创建 feature issue 定义清楚验收点 先写清测试策略,不一定立刻跑
Agent 开发局部逻辑 快速拦低级错误 单元测试
feature 功能完成 验证模块协作 接口测试 / 契约测试
开 PR / 准备合并 防止改动污染主干 冒烟测试 + 必要回归测试
合并到 release 候选 验证集成态稳定性 release smoke test
正式上线前 验证关键用户路径 关键 E2E

一个 issue 模板中应该有的测试部分

## Feature
支持导入新格式的供应商 CSV

## 风险点
- 字段映射变化
- 空值处理
- 导入后列表页显示
- 老格式兼容性

## Required tests
- [ ] 单元测试:字段映射 / 空值处理 / schema 校验
- [ ] 接口测试:导入接口 response / DB 写入结果
- [ ] 冒烟测试:导入后列表页可正���查看
- [ ] E2E:仅在 release 候选时跑"上传 CSV → 导入成功 → 列表可见"主路径

## Merge gate
- 单元测试通过
- 接口测试通过
- smoke 通过

这个模板不是全部的,是在我之前的 issue 模板中增加的部分,以前的 issue 模板可以查看之前的文章。

所有的测试文件,都需要让 agent 在开发的过程中都写好,这篇文章着重讲的是各种测试的使用时机,这些逻辑都可以通过 hook 或者 agent 的 skill 来定义。因为我现在感觉我自己已经是整个开发流程中效率最低的环节了,所以尽量多写一些测试用来降低我的工作量。