关于 tdd
tdd 是一种开发技能,指导以小步、测试先行的方式完成行为变更,适用于需要逐步验证失败情形、可观察行为和重构的编码工作。
主要功能
- 01先建立失败用例
- 02采用可逆小步迭代
- 03测试通过后再重构
- 04验证可观察行为
- 05报告改动与验证结果
适用场景
- 01通过失败测试修复行为
- 02修改前刻画旧代码行为
- 03在测试通过时进行重构
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ robsonrung/ rar-skills --skill tdd安装后在 Claude Code 中输入/tdd确认已加载。
详细介绍
TDD — 测试优先执行
选择分支后,再选择模型。协调工作和确定性命令在调用权限范围内进行。在当前角色中应用此方法。它不会派发工作者。派发工作者时,请使用 shared/references/model-preview.md 及其唯一获批的路线快照。嵌套技能和运行器使用该快照,不再进行其他选择或派发工作者。
铁律
在修复请求的行为之前,先建立一个会失败的行为用例。 如果已捕获的失败能证明同一代码存在同一缺陷,就复用该失败。
- 保留已有的有效工作。不要仅为改变代码历史的顺序而删除并重新创建代码。
- 新测试通过,可能是在描述现有行为。它并不能证明缺少某种行为,也不能证明测试有误。使用相关失败或受控反例来确定它能检测到什么。
步骤 0 — 这是谁的代码?
对于未经测试的遗留代码中的高风险更改,应用 safe-incremental-coding 来补充缺失的特征描述。复用涵盖变更范围的现有行为证据和失败证据。如果已有这些保护措施,则直接继续。
循环
每次行为增量运行一个循环。让每次迭代都足够小,小到可以毫不惋惜地丢弃。
- 确定最小的可逆改动。 只增加一个调用方可见的行为,这是成本最低、可逆的学习步骤,应比直觉认为的还要小。如果无法用一句话说明结果,说明步骤太大;应拆分。选择时说出来:“这里最小的可逆改动是……”
- 先编写测试,预测失败,并确认它确实失败。 从调用方的角度表达代码应做什么。运行前,大声说出预期的失败;如果出现了不同的失败,你已经有所收获。
- 用最简单的方式让测试通过。 只写通过测试所需的最少代码;直接了当即可。这是战术步骤,不是设计步骤,暂时不要打磨。
- 在测试通过的状态下重构。 改进具体的设计问题,然后在进行下一次行为更改前运行受影响的测试。存在代码异味时,使用
clean-code指出异味。必须成立的内部不变量应使用断言:断言是可执行文档,断言失败意味着存在 Bug,而不是一种需要捕获并忽略的情况。 - 集成连贯的增量。 让每个增量都小且通过测试。只有在用户或调用方授权时才提交;根据已完成的行为和通过的检查来选择提交边界,而不是根据计时器。
控制变量
只有能够将效果归因于某个步骤时,你才能从中学习:
- 一次只做一项更改。 不要将重构与行为更改、配置调整捆绑在一起。
- 间歇性测试属于失败,绝不能重跑后将其视为通过。
- 避免巧合式编程。如果代码通过了,要弄清楚原因。
- 绝不钻检查的空子。 禁止为了让测试通过而删除、跳过、弱化、缩小测试范围或用 Mock 规避测试;如果能证明测试实现有误,可在修复权限范围内更正。若要更改已接受的产品契约,则需要作出决策(
shared/references/engineering-rules.md,契约完整性)。
测试编写标准
编写时遵循的规则。当现有测试的价值存疑时,由 test-lens 做判断;以下是编写测试时应遵循的标准,确保它永远不必判定你不合格。
- 风格排序:基于输出(断言纯函数的返回值)> 基于状态 > 基于通信(模拟对象)。通过函数式核心(纯决策)加上可变外壳(精简的 I/O 胶水代码),推动代码采用基于输出的方式。
- 断言可观察行为,绝不检查实现细节。绝不断言对桩对象的调用。
- AAA — Arrange / Act / Assert,各一个 — 使用描述领域行为的语句命名:
delivery_with_a_past_date_is_invalid,而不是testIsValid_case3。 - 难以编写的测试是设计异味——改进设计,而不是测试。
- 重构检验标准:如果用一个完全不同的实现替换当前实现,这个测试仍然有效吗? 应该有效。
设计与风险提示
选择测试和重构方案时使用以下提示;每次集成前无需再进行一轮评审。
- Farley 的五个杠杆:模块化、内聚性、关注点分离、抽象、低耦合。在变更范围内处理这些属性的回归问题。
- “如果……会怎样?”:选择此行为可能暴露的失败场景,例如无效输入、依赖项故障、并发、安全问题或资金损失。复用验收约定中已有的场景和决策。
每步输出约定
每次循环迭代(或一个连贯的批次)后,报告:
changed:编辑了什么。behavior:代码现在新增了什么行为,或保留了什么行为。risk_guarded:此步骤中的测试现在防护的主要设计或数据风险。verification:运行的测试或检查,或无法运行的原因。
路由
- 持久化状态、队列、重试、迁移、外部 API → 复用已批准的 data-systems-coding-lens 发现结果。仅在出现尚未覆盖的数据风险或设计表面发生变化时运行此 lens,而非每次循环迭代前都运行。
- 重构步骤中使用
clean-code处理异味术语和命名。 - 判断现有测试是否值得保留时使用
test-lens。 - 循环中出现无法解释的失败时使用
diagnose。已查明原因的失败或回归留在当前循环中处理;使用现有证据,而不是启动第二轮调查。
注意事项
- 巨型步骤——写了半天代码才第一次运行测试。
- 先实现后测试——贴合现有代码编写的测试可能会漏掉预期行为。根据验收约定和相关反例检查测试;保留有效的工作成果。
- 追逐覆盖率——覆盖率是循环的副产品,绝不是目标。
- 通过测试后再过度设计——在不安全时进行设计;设计应放在重构步骤中。
- “没时间测试”——速度与质量之间不存在取舍;降低返工才是提速之道。
- 不要扩大范围去清理无关代码。
- 不要仅仅因为分层、服务或辅助函数听起来整洁,就添加它们。
- 如果修复无害的局部耦合所增加的间接层多于清晰度,就不要削弱这种耦合。
- 设计需要转向时,通过小步重构实现从通过测试到继续通过测试——改变主意是有成本的;此前小步前进带来的速度,正是为了支付这笔成本。
- 不要引用或还原此技能所提炼的书籍中的原文。
评论
支持 Markdown