专题研修

18|工程质量的核心:契约、测试、反例、Review与交付证据

专题研修约 2.9 千字1 组分步图解

目标:让代码质量成为可检验的结果,而不是要求模型“像资深工程师一样”。实验:第27章真实文件修改、8项功能测试、过期验证拒绝。

本章目录

沿着对象与状态理解本章

契约写成可观察行为,反例证明错误,测试绑定版本,审查补足测试没覆盖的风险。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F34

测试是找反例,不是给代码盖绿章

为什么“测试都通过”仍可能交付错东西?

测试只能验证它实际检查的行为和版本。一条只断言“不报错”的测试无法证明排除规则正确。好的测试围绕需求构造能击中错误的输入;代码修改以后,旧绿色结果也不再自动属于新版本。

反例能让错误实现暴露问题的具体输入。
回归修改破坏了本来成立的行为。
交付证据当前版本对应的检查命令、结果与范围。

输入与适用条件:构造的文件筛选任务;通配符语义须由需求明确,不在动画里偷偷改变“匹配文件名”与“匹配完整路径”的规则。

1 / 6 · 明确需求

第1步,共6步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

测试是找反例,不是给代码盖绿章:明确需求明确需求排除*.tmp,但保留其余文件构造小反例a.py、b.tmp、nested/c.tmp先看原始失败确认旧代码确实没有正确排除实施最小修改修复匹配语义,不改无关API测试针对行为检查保留、排除、嵌套和空规则绑定版本交付绿色结果属于当前代码,而非旧文件教学流程;高亮表示当前步骤,不表示真实耗时比例。

不先说匹配对象与目录语义,无法判断哪个输出才正确。

本步状态由图形与说明共同给出。

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

减少返工和虚假完成,而非让审查循环无限增长。

怎样实现

围绕可观察行为、反例和当前版本组织验证。

可能的代价与误解

测试与实现共用同一错误假设、只测顺利路径、频繁审查无实际修复。

如何判断是否做对

故意引入一处已知错误,测试应失败;恢复后再通过。

1. 先定义行为,再决定流程

一个任务是否成功,首先由用户需要什么、现有系统约束什么、哪些行为不能改变决定。对于exclude功能,必须明确路径相对哪里、目录规则如何匹配、是否支持通配、大小写与分隔符语义。若契约不清晰,AI生成的测试只是在确认自己的猜测。

不应为简单修改写几页形式化规范,但应该消除真正影响结果的歧义。两三条可执行例子常常足够;复杂兼容迁移则需要更细的输入、状态和错误语义。设计深度由实际风险决定。

工程环境也应让Agent容易找到构建、测试与架构边界。OpenAI的Harness工程文章强调把知识和可验证约束放进仓库工作方式;SWE-agent研究则说明操作接口会影响编码结果。这些都不意味着必须购买大型编排平台。[N86][N79]

2. 测试金字塔与目标错误

单元测试快速定位局部逻辑;集成测试检查模块边界、真实存储与协议;端到端测试验证用户流程,但通常更昂贵且更易受环境影响。测试组合应覆盖风险,不是追求某个固定数量比例。

例子:仅测试a.py被排除,无法抓住src/a.py的basename误处理。需要同名不同路径、目录边界、Windows分隔符、空规则和父级跳转等反例。每个断言都应对应一条契约或故障假设,避免大量重复的快乐路径。

测试命令、退出码、测试数量、跳过项和环境都应记录。退出码为零却没有发现任何测试,不是功能通过;因缺少依赖跳过关键测试,也不能被总结为“全部通过”。

3. 性质测试与变形测试

有些行为适合用不变性验证:分隔符归一化后结果相同;无匹配规则时增加不相关规则不改变结果;KV缓存分块方式不改变logits;授权用户改变不能复用他人缓存结果。

变形测试在没有完整答案时,通过输入变换推导输出关系。它能补充样例测试,但关系本身必须正确。比如“增加任何排除规则都不应改变结果”就是错误性质,因为增加匹配规则应改变结果。不要把随意猜出的规律当作真理。

数值实现适合用有限差分、守恒量、对称性和高精度基线;Agent流程适合用故障注入、权限边界和版本冲突。把所有东西都交给LLM打分,会失去确定性机制可以提供的强证据。

4. Mutation:证明测试真的能抓错

把因果掩码删掉、把RoPE位置重置、把缓存键中的用户身份拿掉、让finish忽略版本,再运行测试。预期对应测试失败,说明它们对目标错误敏感。如果故意引入Bug仍然全绿,测试覆盖了代码行却没覆盖语义。

Mutation分数也不能单独代表质量。很多机械突变没有业务意义,有些等价变换不应导致失败。优先针对真实失败模式设计负对照,比盲目追求杀死所有变异更有价值。

快照测试适合稳定输出契约,但对自然语言说明、技能全文或无关格式使用固定hash,会让每次合理编辑都变成回归噪声。测试应绑定需要保持的行为,不应绑定整个文本恰好长这样。

5. Review怎样避免成为无限循环

Google的评审标准强调改善整体代码健康度,不追求无限完美。实际审查可围绕设计、功能、复杂度、测试和可读性;小问题可以直接修复并重新验证,不必每次重启方案设计。[N50]

优先检查高后果问题:错误数据写入、竞态、事务边界、兼容破坏、权限扩大、测试被弱化。风格问题在项目已有工具可处理时交给工具。不要让命名偏好掩盖功能缺陷,也不要用“不是大问题”忽略真实风险。

独立Review适合复杂或高风险变化;简单配置修改加聚焦测试可能就足够。评审成本应与减少的缺陷、返工和事故相比较。如果某个流程只延长任务而没有可观察收益,应精简。

6. 验证新鲜度与工件归属

测试通过必须对应当前代码。测试后又修改文件,旧结果不能自动继续有效。本书通过文件版本哈希检测这一点;更大型系统可按依赖范围复用测试结果,但需要可靠依赖与构建缓存,不应凭模型判断“只是小改动”就跳过必要验证。

还需保护用户未提交修改,检查本次diff范围,识别生成文件、锁文件和配置变化。模型可能修复局部问题同时删掉有意保留的代码,最终报告必须按真实diff核对,而不是凭聊天记忆列出文件。

部署也是独立动作。代码通过本地测试不等于已经上线;PR合并不等于生产健康;回滚方案是否可用取决于数据迁移与外部副作用。报告应明确每个阶段完成状态,不虚构生产验证。

7. 一份简洁但充分的交付

内容包括:改了什么行为、为什么需要、主要影响范围、运行了什么验证、剩余限制。复杂任务可附关键决策理由;简单任务不必塞满模板。如果证据不足,应具体指出缺什么,而不是用“建议进一步测试”泛泛结束。

验收题:模型补丁通过全部现有测试,却不满足用户新要求,责任在哪?测试集没覆盖新契约,不能以旧测试替代需求验收。应增加针对新行为的测试,并检查旧行为是否仍保留。AI工程质量首先还是软件工程质量。

运行示例 · S18

性质测试用一个族的输入抓住前缀错误

输入与条件。排除目录d。正确关系是d本身和d/child排除,d_suffix保留。

步骤与对象内部动作中间结果 / 新状态
1实例1d="a"a、a/x排除,ab保留。
2实例2d="cache"cache/tmp排除,cached保留。
3生成族改变d与后缀重复同一边界性质。
4变异实现把边界检查替成startswith(d)多个反例稳定击中错误。
5约束范围先规范化路径与分隔符否则字符串生成可能不对应真实路径语义。

把过程连起来。性质测试把需求变成对一类输入的关系,变异或反例用来检验测试是否真能抓错。

边界与反例。通过有限生成样本不证明所有路径正确;平台与安全边界需要单独验证。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。