22|工程质量:从需求到测试,再到真正可交付的代码
本章目录
本章预备知识
代码能运行不等于功能正确,通过测试也取决于测试能否检出原缺陷。先找反例,再验证修改,再证明证据确实对应当前代码版本。
本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。
进入深读前的小检查:把总返回成功的假实现放进测试,看看会不会仍全绿。若会,先增强测试区分力而不是增加更多同类样例。
术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。
这一章把“最佳实践”拆成适用场景和可验证行为。不存在对所有任务都最优的固定Analysis→Task→Review长链。
沿着对象与状态理解本章
先写出要守住的行为,再用会失败的反例证明确实需要修改。测试通过必须绑定被测代码版本;之后再改文件,旧绿色结果不再证明当前交付。
下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。
测试是找反例,不是给代码盖绿章
为什么“测试都通过”仍可能交付错东西?
测试只能验证它实际检查的行为和版本。一条只断言“不报错”的测试无法证明排除规则正确。好的测试围绕需求构造能击中错误的输入;代码修改以后,旧绿色结果也不再自动属于新版本。
输入与适用条件:构造的文件筛选任务;通配符语义须由需求明确,不在动画里偷偷改变“匹配文件名”与“匹配完整路径”的规则。
1 / 6 · 明确需求
窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。
不先说匹配对象与目录语义,无法判断哪个输出才正确。
本步状态由图形与说明共同给出。默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。
为什么需要
减少返工和虚假完成,而非让审查循环无限增长。
怎样实现
围绕可观察行为、反例和当前版本组织验证。
可能的代价与误解
测试与实现共用同一错误假设、只测顺利路径、频繁审查无实际修复。
如何判断是否做对
故意引入一处已知错误,测试应失败;恢复后再通过。
Q085|怎样把模糊需求变成Agent能验证的完成条件?
核心回答
先明确期望行为、边界条件、不允许改变的约束和可观察验证方式。测试不是最后才写的附属品,而是把需求转成可检查事实的一种方式;但并非所有设计质量都能由测试覆盖。
将“增加exclude功能”拆成可检查语义
要明确规则基准目录、通配符语义、空规则行为、目录与文件的关系、大小写/分隔符、非法输入处理,以及已有include规则的优先级。不是每项都需新增机制,先从现有设计和用户目标确定实际需要。
例如定义:未配置exclude时行为不变;匹配的路径不进入输出;未匹配路径保持原顺序;相同输入与配置输出确定。这样可以构造普通案例、边界案例和性质测试。若用户没有要求新匹配语法,就不应擅自引入复杂DSL。
实现前用当前代码跑一个应失败的案例,证明需求差距;实现后同案例应通过,再补相邻回归。对于无法本地复现的生产故障,明确替代证据与限制,不把“没有报错”当完成。
把“支持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规则不应让原本被排除路径重新出现”,但前提是需求确实满足这个单调性。错误性质会限制合法行为,所以要先证明或明确适用条件。
测试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任务,会制造沟通成本和上下文重复。
应区分阻塞问题与建议,但不必建立繁复级别体系。清楚说明问题会造成什么、证据是什么、最小修复是什么,比打一个抽象风险分数更有用。
同样是改一行,为什么审查投入不同
输入与条件。任务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。
把文档空格改了,为什么哈希测试红了但功能没坏
输入与条件。测试把技能全文SHA256固定为h1。作者只调整了一处空行,新哈希变h2。
| 步骤与对象 | 内部动作 | 中间结果 / 新状态 |
|---|---|---|
| 1哈希观察 | 内容字节变动 | h1≠h2,测试红。 |
| 2语义核验 | 触发描述、资源路径和行为未变 | 哈希不能证明专业能力退化。 |
| 3有效测试 | 检查技能元数据可解析、关键引用可读、正反例路由行为 | 针对真正功能。 |
| 4合理哈希用途 | 验证下载工件、基线文件未被并发篡改 | 此时字节一致性正是目标。 |
| 5取舍 | 删除不必要的全文快照门槛 | 不等于删除所有完整性检查。 |
把过程连起来。测试应断言你真正想保持的不变量;文本字节与业务行为是两类不变量。
边界与反例。语义行为评测通常有模型随机性,需要固定环境与统计,而不能只换一个更宽松字符串断言。
依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。
追问:LLM路由非确定,行为测试怎么稳定?
区分确定性配置检查与统计路由评测。固定模型、Prompt、任务与预算,运行多次或用足够任务量,报告分布和边界失败。不要要求每次措辞完全相同;关注必须满足的选择与结果。
追问:路由正确就能说明代码质量提高吗?
不能。加载技能可能没有被使用,或技能本身质量差、导致过度流程。需要下游任务指标。路由是中间指标,最终还看正确性、工程合理性与成本。
追问:怎样建立最小有效回归集?
从真实失败收集少量高价值案例,包含原问题、边界反例和未受影响场景。每次改动补能防止同类退化的测试,不为每个句子新增结构断言。随着失败分布变化更新,而不是无限堆积无效用例。