51 务实的入门套件
以版本控制事件驱动构建、测试和发布,配合破坏测试与状态覆盖形成可重复交付底座。
学习目标
- 能让一次版本提交触发可追踪的构建、测试、发布和监测证据
- 能通过自动测试、破坏测试和状态覆盖发现测试盲区,而不只看代码覆盖率
- 能对失败制品定位首个差异、按版本回退,并把同一缺陷变成长期回归
51 务实的入门套件
本页依据 David Thomas、Andrew Hunt《程序员修炼之道:通向务实的最高境界(第2版)》,云风译,电子工业出版社,2020 年 4 月,ISBN 9787121384356 的公开中文目录,独立重构 51 务实的入门套件。正文、代码、图示、实验和练习都是本课程重新设计的教学材料,不复制原书正文、插图或答案。
一个务实的入门套件不是一堆脚本,而是一条能被重放的交付路径:版本变化触发构建,构建触发测试,测试决定是否发布,发布产生运行和用户反馈。自动化的价值在于把机械步骤变成证据;它不能替人判断语义风险,却能让一次失败不会只发生在某个开发者的电脑上。
三个会让流水线产生假安全的陷阱
五个词构成可重放底座
<Term def="由版本变化触发后续构建、测试、发布和监测的可追踪交付起点。">入门套件</Term>把一个人的本地流程变成团队共享的最小系统。它应能在新环境中安装、运行并指出缺失依赖。
<Term def="在版本事件后自动执行构建、检查、测试和制品保存的反馈系统。">持续集成</Term>让问题靠近提交被发现。它不只是频繁合并,而是每次变化都有明确的输入、结果和责任。
<Term def="用可重复输入验证行为、状态、错误和用户边界,并在失败时阻止错误继续传播的检查。">自动测试</Term>要覆盖用户真正关心的结果。测试失败应包含足够上下文,让修复者可以重现。
<Term def="有意改变实现或注入缺陷,检查测试是否真的能识别行为变化的验证方法。">变异测试</Term>把测试套件当作待验证的程序。一个变异没有被杀死,就意味着测试可能只证明代码被执行。
<Term def="按用户可达状态、转换、拒绝、恢复和数据条件组织测试证据的范围。">状态覆盖</Term>补足行覆盖看不见的风险。团队应说明哪些状态已验证,哪些仍然只能人工观察。
这条底座链从提交开始,不以“命令成功”结束,而以可追踪制品、用户状态、失败回退和缺陷回归收口。
提示89:使用版本控制来驱动构建、测试和发布
版本提交是交付链的事件身份。它应当关联源代码、依赖、构建参数、制品摘要、测试结果、发布环境和回退版本。若发布只能依赖某个人记得一条命令,团队就无法在相同输入下重建结果。
提示90:尽早测试,经常测试,自动测试
测试越早接近假设被写下的地方,失败上下文越少。自动化不是为了让所有测试都变成同一种速度,而是让关键反馈稳定出现;慢而有价值的端到端样本可以分层运行,但不能被静默跳过。
提示91:直到所有的测试都已运行,编码才算完成
“所有”要有范围定义:哪些用户状态、错误路径、权限、数据边界和恢复动作属于这次切片。没有运行的测试必须有明确原因、负责人和风险决定,不能把未执行隐藏在绿色摘要中。
提示92:使用破坏者检测你的测试
破坏者可以是被删除的断言、改变的边界、错置的权限或被替换的依赖。好的测试应让这些有意义的变化失败;如果破坏者全部通过,首先修测试和状态模型,而不是继续堆覆盖率数字。
提示93:测试状态覆盖率,而非代码覆盖率
状态覆盖关注用户和系统走过什么路径:新建、处理中、成功、拒绝、超时、重试、回退和恢复。一个分支可能被执行,却从未检查状态是否被错误地持久化或重复转移。
提示94:每个 Bug 只找一次
一次缺陷修复应同时补上能重现它的回归,说明哪个状态和哪条边界被遗漏。这样同一问题不会靠记忆在每次发布前重新寻找;测试名称和失败输入应让后来者理解原因。
提示95:不要使用手动程序
能被脚本可靠执行的步骤就不应依赖个人手工。人工批准仍可能是必要的治理动作,但它应发生在可追踪输入和可回退制品上,并留下决定、责任人和时间。
代码实验:让提交成为可重放事件
type PipelineRun = {
revision: string;
artifact: string;
testStates: string[];
killedMutations: string[];
rollbackRevision: string;
};
function canPromote(run: PipelineRun) {
return (
run.revision.length > 0 &&
run.artifact.length > 0 &&
run.testStates.length > 0 &&
run.killedMutations.length > 0 &&
run.rollbackRevision.length > 0
);
}这个检查把版本、制品、状态测试、破坏验证和回退放在一起。它不是完整发布系统,却能阻止“测试跑过了”替代“这次制品可追踪、可恢复且状态边界被验证”。
练习可重放的交付底座
Interactive lab
选择流水线样本,定位交付门禁的首个变化
输入证据
删除一个关键断言后代码覆盖率仍然很高,测试套件没有失败。
实际首差
破坏节点:执行覆盖存在,但行为结果没有被验证。
恢复动作
把破坏者变成回归,补边界断言并重新运行;未杀死前阻止发布。
先查看状态矩阵和破坏结果,再选择流水线样本;绿色摘要不能替代可回退证据。
1. 画提交到发布的事件链
选择一个小改动,写出提交、构建、测试、制品、发布、监测和回退的输入输出。指定版本身份、负责人和每个阻塞条件,找出仍依赖手工记忆的节点。
正常、边界与单一故障证据
| 样本 | 只改变的变量 | 预期判定 | 必存证据 |
|---|---|---|---|
| 正常 | 提交、依赖和完整测试 | 制品可追踪并安全发布 | 版本、制品、测试和环境摘要 |
| 边界 | 状态、权限或资源阈值 | 在错误传播前拒绝或暂停 | 状态输入、决定、日志和责任人 |
| 单一故障 | 一个测试、依赖或发布步 | 首个异常点暴露并按标签回退 | 首差、失败输入、回退和回归 |
覆盖率、构建绿灯和截图只能提供局部证据。完整底座还要证明错误会被发现、制品能被定位、状态能被恢复、同一缺陷不会再次依赖人工记忆。
术语表
名词解释
本章出现的专业名词,用大白话再讲一遍。
- 入门套件
由版本变化触发后续构建、测试、发布和监测的可追踪交付起点。
- 持续集成
在版本事件后自动执行构建、检查、测试和制品保存的反馈系统。
- 自动测试
用可重复输入验证行为、状态、错误和用户边界的检查。
- 变异测试
有意改变实现或注入缺陷,检查测试是否能识别行为变化的验证方法。
- 状态覆盖
按用户可达状态、转换、拒绝、恢复和数据条件组织测试证据的范围。
练习
练习
问题 1: 一个提交能构建并通过单元测试,但发布后重试会重复扣款。入门套件缺了什么?
问题 2: 代码覆盖率达到 95%,一个删除断言的破坏者仍然通过。下一步做什么?
问题 3: 发布必须由人工批准,但团队想消除所有人工步骤。如何区分治理和手工程序?
本单元回顾
务实的入门套件让一次提交带着构建、测试、制品、发布、监测和回退证据走完整条路径。自动化不等于盲目追求绿色数字:要用状态覆盖识别用户边界,用破坏者检验测试质量,用回归记录让每个缺陷只被发现一次,并让第二个人能按版本重建和恢复。