系统篇

22|工程质量:从需求到测试,再到真正可交付的代码

系统篇约 5.3 千字1 组分步图解
本章目录

本章预备知识

代码能运行不等于功能正确,通过测试也取决于测试能否检出原缺陷。先找反例,再验证修改,再证明证据确实对应当前代码版本。

本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。

进入深读前的小检查:把总返回成功的假实现放进测试,看看会不会仍全绿。若会,先增强测试区分力而不是增加更多同类样例。

术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。

这一章把“最佳实践”拆成适用场景和可验证行为。不存在对所有任务都最优的固定Analysis→Task→Review长链。

沿着对象与状态理解本章

先写出要守住的行为,再用会失败的反例证明确实需要修改。测试通过必须绑定被测代码版本;之后再改文件,旧绿色结果不再证明当前交付。

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

动态图解 · F34

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

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

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

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

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

1 / 6 · 明确需求

第1步,共6步

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

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

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

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

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

为什么需要

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

怎样实现

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

可能的代价与误解

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

如何判断是否做对

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

Q085|怎样把模糊需求变成Agent能验证的完成条件?

核心回答

先明确期望行为、边界条件、不允许改变的约束和可观察验证方式。测试不是最后才写的附属品,而是把需求转成可检查事实的一种方式;但并非所有设计质量都能由测试覆盖。

将“增加exclude功能”拆成可检查语义

要明确规则基准目录、通配符语义、空规则行为、目录与文件的关系、大小写/分隔符、非法输入处理,以及已有include规则的优先级。不是每项都需新增机制,先从现有设计和用户目标确定实际需要。

例如定义:未配置exclude时行为不变;匹配的路径不进入输出;未匹配路径保持原顺序;相同输入与配置输出确定。这样可以构造普通案例、边界案例和性质测试。若用户没有要求新匹配语法,就不应擅自引入复杂DSL。

实现前用当前代码跑一个应失败的案例,证明需求差距;实现后同案例应通过,再补相邻回归。对于无法本地复现的生产故障,明确替代证据与限制,不把“没有报错”当完成。

运行示例 · Q085

把“支持exclude”变成可以验收的输入输出表

输入与条件。需求:exclude=["a"]时不构建a及其子目录,但ab仍参与;空exclude不改变原行为。

步骤与对象内部动作中间结果 / 新状态
1正常路径输入a、a/x预期均排除。
2相邻反例输入ab/x预期保留,区分目录边界与字符串前缀。
3空集合exclude=[]所有原候选仍按原规则处理。
4异常条件路径是否规范化、大小写是否敏感先查实际平台要求,不能凭空追加跨平台承诺。
5验收对当前补丁运行这组行为测试通过后再看是否有真实集成风险。

把过程连起来。验收不是“代码能运行”,而是覆盖能区分正确实现与常见错误实现的输入。

边界与反例。示例需求仅含声明条件;生产项目还需按真实目录、构建系统与用户约束补充。

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

追问:Acceptance Criteria会不会让小任务复杂化?

可以只是一两句明确行为,不必专门文档或审批。复杂度来自需求风险,而不是名称。一个字段改名可能只需构建和对应测试;支付状态机变更需要更多边界。

追问:模型自己写测试会不会自证正确?

有这种风险。实现和测试可能共享同一误解。可从用户需求、旧Bug、独立参考实现或不变量生成测试,并保留隐藏/独立验证。测试通过说明满足这些断言,不证明断言覆盖全部意图。

追问:怎样防止Agent偷偷扩大范围?

对比最终diff与授权目标,检查新增依赖、公共接口、数据迁移和无关格式化。范围约束可在任务开始明确,结束时机械加人工/模型审查结合。不是限制所有合理重构,而是要求它有必要性和证据。

Q086|为什么测试全绿仍可能是假完成?怎样识别弱测试与过期验证?

核心回答

测试可能没运行目标、被跳过、断言太弱、验证旧版本或环境错误。需要把测试命令、实际执行数量、退出状态、版本和断言意义连接起来,而不是只看一个绿色图标。

六种看起来成功的反例

命令选错目录导致0个测试;筛选表达式只跑了无关用例;失败测试被标记skip;断言只检查结果非空而没检查排除路径;测试在补丁前跑过,补丁后未重跑;mock总是返回成功,根本没经过真实分支。

更强的验证会显示:哪些测试执行、哪些跳过及原因,目标失败能否在旧版复现,新版是否通过,最终版本与日志是否一致。对重要逻辑可做mutation test:故意把关键条件反转、移除幂等检查,测试应该失败。若仍全绿,说明断言没有保护那条行为。

性质测试可以覆盖大量输入关系,例如“增加exclude规则不应让原本被排除路径重新出现”,但前提是需求确实满足这个单调性。错误性质会限制合法行为,所以要先证明或明确适用条件。

运行示例 · Q086

测试100%通过,为什么补丁仍然可能错误

输入与条件。测试只有“函数返回一个列表”,错误实现永远返回空列表也能通过。

步骤与对象内部动作中间结果 / 新状态
1观察断言只检查类型没有检验列表成员与需求。
2构造坏实现始终return []测试绿,但正常文件全被漏掉。
3加强性质空exclude时输出应与原始候选一致立刻区分坏实现。
4增加反例排除a时仍必须包含ab/x覆盖真正边界。
5版本核验测试在补丁前v7运行、补丁后已v8旧绿灯不能用于v8交付。

把过程连起来。测试数量与通过率只说明给定断言的结果;断言质量和目标版本决定证据价值。

边界与反例。不能由一个反例证明全部正确,但可以明确否定一个错误实现。

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

追问:覆盖率100%是否足够?

行覆盖只说明执行到了,不说明断言检查了正确结果;分支覆盖更细,但仍不能覆盖所有状态组合、并发与业务语义。覆盖率可帮助发现空白,不是质量保证书。

追问:Mock和真实集成测试怎样取舍?

Mock使测试快速确定,适合隔离局部行为;真实集成验证协议、配置和边界。若全部mock,可能错过实际API格式和事务行为;若全部端到端,反馈慢且易波动。按风险分层,不必对每个函数都搭完整环境。

追问:测试后只改注释,还需要重跑全部吗?

通常不需要全量重跑,但要确认确实只改非执行内容。测试、配置、代码生成输入或嵌入指令有时看似文本却影响行为。验证范围应与实际影响匹配,既避免形式主义,也避免漏掉可执行语义。

Q087|Review什么时候值得?怎样避免分析—审查—重设计无限循环?

核心回答

Review应发现实现者或自动测试可能遗漏的重要问题,按风险与证据选择深度。局部小问题可直接修复并验证;只有推翻关键设计或扩大影响范围才需要重新分析。目标是改善代码健康度,不是追求所有细节完美。[REVIEW]

按错误后果选择审查方式

一处文案或私有函数局部改动,编译与针对性测试可能已足够。跨模块接口、并发、数据迁移、权限和不可逆部署值得检查不变量、兼容和恢复。独立Reviewer最好带明确任务,例如寻找旧调用方回归或竞态,而不是泛泛挑毛病。

若Review发现变量名不清、遗漏一个边界测试,直接在当前任务修正即可。若发现架构假设错误、数据模型无法表达需求,再回到设计。把每个低风险意见都转成新Analysis任务,会制造沟通成本和上下文重复。

应区分阻塞问题与建议,但不必建立繁复级别体系。清楚说明问题会造成什么、证据是什么、最小修复是什么,比打一个抽象风险分数更有用。

运行示例 · Q087

同样是改一行,为什么审查投入不同

输入与条件。任务A改文档拼写;任务B把转账余额判断从>=改成>。两者都只改一个字符。

步骤与对象内部动作中间结果 / 新状态
1风险识别A影响阅读,B影响业务边界改动行数不能独立代表风险。
2A验证检查拼写与相关格式不需要架构分析和多Agent交叉审查。
3B验证检查余额等于金额、并发更新、失败回滚需要与真实契约对应的测试与审查。
4小问题处理审查发现局部命名错可直接修并重跑相关检查,不必重新设计整个方案。
5停止风险已被适当证据覆盖不为追求形式完美无限增加轮次。

把过程连起来。审查应随失败后果、隐藏依赖与可验证性变化,不跟“修改几行”或固定流程机械绑定。

边界与反例。金融情景仅用于展示风险差异,不提供真实转账实现或上线建议。

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

追问:Reviewer能否修改代码?

可以,只要任务授权与工具允许,并记录修改与验证。角色分离是为了独立视角,不是禁止修复。Review中直接修正明确小问题常更高效;重大变更仍需与主任务协调,避免偷偷改变方向。

追问:多次Review是否一定越来越可靠?

边际收益通常取决于新证据和新视角。重复同样检查可能只产生风格争议,还可能引入新错误。应观察历史缺陷检出和返工成本,设定明确停止条件。

追问:怎样审查“过度工程化”?

问每个新抽象、规则、状态或服务阻止了什么具体错误;没有它会发生什么;有没有更简单的实现;成本是否与风险相称。不能因为某模式常见就默认必须使用,也不能因为追求简单而删除真实必要的安全边界。

Q088|测试Skill或Prompt为什么不宜大量使用hash快照?应该测什么?

核心回答

文本hash证明内容字节未变,不证明行为正确。对于会合理演化的技能描述和Prompt,过多hash测试会把正常编辑变成更新指纹的负担。应优先测试发现、路由、必要约束和真实任务行为;精确hash适合确实要求不可变的产物身份。

区分四种测试对象

语法测试检查SKILL元数据可解析、必需字段和引用文件存在。结构测试检查资源关系与工具schema合法。行为测试给定任务,观察是否选到必要技能、是否执行相关验证。集成测试在真实仓库任务中比较代码结果、回归和成本。

一个description把“数据库查询”改为“SQL与数据库查询”,hash会变,但功能可能更好;行为测试应该允许这种改进。相反,删除一句关键禁止条件后文档仍格式正确,只有相应负例才能暴露风险。

可以保留少量快照用于审查整体变化,但把快照作为review辅助,而非唯一质量门槛。对执行脚本、固定证据包或缓存键,内容hash仍有明确用途;不要把反对脆弱测试误解为禁止所有hash。

运行示例 · Q088

把文档空格改了,为什么哈希测试红了但功能没坏

输入与条件。测试把技能全文SHA256固定为h1。作者只调整了一处空行,新哈希变h2。

步骤与对象内部动作中间结果 / 新状态
1哈希观察内容字节变动h1≠h2,测试红。
2语义核验触发描述、资源路径和行为未变哈希不能证明专业能力退化。
3有效测试检查技能元数据可解析、关键引用可读、正反例路由行为针对真正功能。
4合理哈希用途验证下载工件、基线文件未被并发篡改此时字节一致性正是目标。
5取舍删除不必要的全文快照门槛不等于删除所有完整性检查。

把过程连起来。测试应断言你真正想保持的不变量;文本字节与业务行为是两类不变量。

边界与反例。语义行为评测通常有模型随机性,需要固定环境与统计,而不能只换一个更宽松字符串断言。

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

追问:LLM路由非确定,行为测试怎么稳定?

区分确定性配置检查与统计路由评测。固定模型、Prompt、任务与预算,运行多次或用足够任务量,报告分布和边界失败。不要要求每次措辞完全相同;关注必须满足的选择与结果。

追问:路由正确就能说明代码质量提高吗?

不能。加载技能可能没有被使用,或技能本身质量差、导致过度流程。需要下游任务指标。路由是中间指标,最终还看正确性、工程合理性与成本。

追问:怎样建立最小有效回归集?

从真实失败收集少量高价值案例,包含原问题、边界反例和未受影响场景。每次改动补能防止同类退化的测试,不为每个句子新增结构断言。随着失败分布变化更新,而不是无限堆积无效用例。

记录保存在本机浏览器。

输入关键词即可检索。

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

阅读设置

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