跳转至

测试全绿以后,交付为什么还可能是断的

测试集合连续运行两次都通过。你执行 git add .,准备提交,随后发现准备提交的 差异还包含半写的 Dockerfile;README 的集成测试命令使用了不存在的 unit marker; 一处新依赖也没有进入声明文件。

绿色测试是重要证据,但工程交付还要求首次进入者能复现入口、审阅者能理解变更 意图、文档与当前行为一致。否则“在我机器上通过”仍然没有成为可移交的基线。

材料说明

本章使用 Git 当前官方语义、Markdown README 和前五章形成的 pytest 配置。不会 实际修改主项目或强制提交,也不规定分支模型与 commit message 规范。

1. README 应让下一位读者完成任务

README 不是愿望清单,也不是把所有配置复制一遍。对于当前阶段,首次进入仓库的 人至少应能找到:

  • 项目做什么、当前提供什么;
  • Python 与依赖准备入口;
  • 服务启动命令;
  • 单元、集成和完整测试命令;
  • API/OpenAPI 入口;
  • 当前限制:没有数据库、认证、真实 provider、Docker 或 CI。

测试段落可以是:

## 验证

以下命令均从仓库根目录运行:

- 单元测试:`python -m pytest tests/unit`
- FastAPI 进程内集成测试:`python -m pytest -m integration`
- 完整集合:`python -m pytest`

pytest 的发现路径与 marker 定义以 `pyproject.toml` 为准。
测试使用可控 adapter,不访问真实外部 API。

这段说明把任务入口交给读者,把 marker 的权威定义留在配置。若 README 复制一份 marker 列表、配置又维护另一份,两者迟早漂移。

最危险的文档错误不是“不够漂亮”,而是描述未实现行为:当前没有 Docker 就不要 写 docker compose up;没有 CI 就不要显示虚构徽章。文档应概括当前事实并明确 限制。

2. 你编辑的、暂存的、将提交的不是同一个集合

W01-L01-P05 已经区分了工作区、index 和 commit。这里继续使用同一组三层快照:

working tree --git add--> index --git commit--> commit
     当前文件             下一快照          历史快照

git status 区分已暂存、未暂存和未跟踪路径;但只看文件名不够。提交前至少分别 复核:

概念|staged diff index 与 HEAD 之间的差异,也就是当前准备进入下一次 commit 的内容;它不等于 编辑器里全部当前文件,也不包含尚未暂存的修改。

# working tree 与 index 的差异:尚未暂存
git diff

# index 与 HEAD 的差异:当前准备提交
git diff --cached

设想 README 中“测试命令修正”已经暂存,随后你又在同一文件写了 Docker 草稿但未 暂存。git diff --cached 只显示前者;git diff 显示后者。commit 记录的是 index 中选定内容,不是编辑器里整个文件的当前样子。

同一个文件完全可能同时有 staged 与 unstaged hunk。选择性暂存的意义就在于构造 语义快照;它不能替代验证,但能避免无关草稿混入交付。

3. 单一意图可以跨越代码、测试、配置和文档

概念|语义 commit 边界 围绕一个可独立审阅的工程结果,组织使该结果成立所需的代码、测试、配置和文档; 无关重构或尚不可运行的草稿应分离。

“一个 commit 一个意图”不等于“一种文件一个 commit”。建立测试基线可能需要:

实现修正        让业务错误稳定映射为 409
单元测试        证明 core 冲突规则
集成测试        证明 FastAPI 公开 409
pytest 配置     注册 integration marker
README          暴露三类验证入口

这些改动共同使“建立成功与错误路径测试基线”成立,可以作为一个可独立审阅的 工程意图。反之,一次顺手的无关模块重命名、全仓格式化或 Docker 草稿应分离。

按文件类型机械拆成“先提交代码、再提交测试、最后提交文档”,会产生语义不完整的 中间快照:代码变了却没有验证,测试命令变了 README 仍旧过期。是否同组取决于 意图完整性,而非后缀名。

提交消息应概括结果,例如:

feat(W01-L04): 建立成功与错误路径测试基线

若 diff 看不出动机,可在正文补充为何选择进程内 ASGI 边界或为何暂不引入数据库。 “update tests”只描述动作,没有帮助审阅者理解结果。

4. 用一条链审查整套交付

概念|可复核交付基线 契约、测试、配置、README 与 Git 快照互相一致,并能由下一位读者从仓库入口复现。 它证明交付可检查,不证明软件没有任何 bug,也不代表课程已经学习完成。

交付前分两段按因果链复核。

从契约走到可重复测试

契约与风险
单元/集成边界
成功、校验、业务错误 oracle
fixture 与状态隔离
单层、完整、重复运行入口

先检查:

  1. 验证清单中的每项核心目标是否有合适层级?
  2. core 单元是否证明规则,HTTP 集成是否经过真实 FastAPI 应用?
  3. 201、422、409 是否有具体公开断言,而不是任意成功/错误?
  4. 测试是否不访问真实外部服务,fixture 是否恢复状态?

从测试入口走到候选提交

单层、完整、重复运行入口
README 当前说明
staged diff 与单一 commit 意图

再检查:

  1. 单元、集成、完整集合是否可发现、可选择并连续运行一致?
  2. README 命令是否从仓库入口可执行,与 pyproject.toml 一致?
  3. git diff --cached 是否只包含这一意图所需的实现、测试、配置与说明?

这个审查只证明交付内容形成了可复核基线,不能证明软件没有任何 bug,也不能证明 学习者已经掌握相关能力。测试和文档都是证据,不是全知证明。

常见误区

  • git status 干净就说明提交正确。 它不替你审查每个 staged hunk 的语义。
  • 代码、测试、文档必须分 commit。 同一意图的跨文件改动可以且常常应该共同出现。
  • README 越长越完整。 入口可定位、事实当前且权威来源明确,比复制所有细节重要。
  • 测试全绿即可交付。 漏收集、过期命令、缺依赖声明和混合 diff 都可能让交付断链。

本章小结

pytest 基线要成为工程交付,必须同时具备可复现入口和可审阅快照。README 从实际 配置提炼任务导航;Git index 精确决定下一 commit;commit 围绕一个工程意图组织 必要代码、测试、配置与文档。最终审查把契约、测试、隔离、运行、说明和 diff 连成一条可追溯链。

练习

一个候选 staged diff 包含:

  • 修正 PlanConflict → 409;
  • 新增 core 冲突单元测试;
  • 新增 HTTP 409 集成测试;
  • 注册 integration marker;
  • README 新增完整测试命令;
  • 重命名三个与测试无关的 domain 模块;
  • 增加尚不可运行的 Dockerfile 草稿。

请给出 commit 分组,并说明提交前还要复核哪些证据。

练习解析

前五项共同构成“建立业务冲突测试基线”:实现让契约成立,单元/集成分别证明规则 与公开映射,配置提供集合入口,README 让入口可发现。它们可以进入同一 commit。

无关 domain 重命名属于另一个重构意图,应分离;Dockerfile 属于 W01-L05 Target, 当前尚不可运行且越出本课,应从本次 staged diff 排除。

提交前还应:运行 collect 检查;分别运行单元、集成和完整集合;连续运行完整集合; 核对测试不访问外部服务;从 README 复制命令实际执行;检查 git diffgit diff --cached;确认依赖声明、配置和说明都在 staged 快照中,且未包含本地 生成物或 secret。

参考资料