
“AI 软件开发实战教程”系列第 8 篇:用第一个 TDD 节点建立可复现工程、统一验证命令和诚实的环境边界,为后续业务开发准备一条不会越走越乱的跑道。
上一篇把邻行拆成了十个纵向开发任务,但真正开始写邀请注册以前,计划里还有一个看起来不那么像产品功能的 V0:工程骨架与验证契约。
它没有漂亮页面,也没有匹配算法。它只回答几件基础问题:
新环境怎样安装项目; Web、后台任务和数据库怎样启动; 修改代码后最少要运行哪些检查; 配置错误能不能在启动时暴露; 时间和第三方提醒怎样在测试中稳定替换; 浏览器测试究竟验证了什么,还有什么没有验证。
这些问题如果不先回答,后面的 TDD 很容易变成“在我的机器上偶尔能跑”。
1. 工程骨架不是先写一堆空目录
有一种常见的“搭架子”方式,是一次创建所有计划中的模块、模型和接口,每个文件先留一个空类。目录看起来很完整,实际上没有一条命令能证明这些东西能够协同运行。
邻行的 V0 只实现后续任务现在就需要的基础能力:
Python 3.12 + Django 5.2 LTS ├─ 分层设置与生产配置校验 ├─ 第一条自定义用户迁移 ├─ 存活与就绪健康检查 ├─ 可注入时钟 ├─ 假提醒渠道 ├─ 空通知 Worker └─ pytest / Ruff / mypy / Playwright社区、出行、匹配、交换等模块没有为了“结构完整”提前创建。它们会在对应纵向任务中,由真实失败测试推动出现。
2. 第一个红灯必须因正确原因失败
TDD 的第一步是 RED,也就是先看到测试失败。
这不等于故意写错断言。红灯必须说明目标能力确实还不存在。
V0 最先写了几类测试:
生产环境缺少密钥、允许域名或数据库地址时拒绝启动; 健康端点返回明确状态; 项目从第一条迁移使用自定义用户模型; 固定时钟拒绝没有时区的信息; 假提醒渠道只记录消息,不访问真实网络。
第一次运行得到的核心错误是:
No module named linxing.settings这是有效红灯,因为项目配置此时确实不存在。它不是数据库没开、依赖没装或测试拼错名字造成的偶然失败。
随后只创建满足这些测试的最小 Django 工程。测试变绿以后,再整理重复配置和模块边界。
3. 版本选择要服从可验证环境
架构初稿曾把 Python 3.13 作为目标,但真正进入 V0 后发现当前开发机只有 Python 3.12.3。
这时有两个选择:
文档继续写 3.13,代码却偷偷用 3.12; 把事实源调整为实际可执行、同时受 Django 5.2 LTS 支持的 3.12。
邻行选择了第二种。
版本规划不是愿望清单。教程如果宣称“已经验证 Python 3.13”,却从未在该版本运行测试,后续读者会把一个假设当成证据。
项目仍允许 Python 3.12 到 3.13,但当前检查点只声称 3.12.3 已经实际运行。
4. 把常用验证变成统一入口
随着工具增加,开发者很容易记住不同版本的命令:有人只跑单元测试,有人忘了格式检查,有人直接跳过浏览器。
V0 用 Makefile 和 HARNESS.md 固化了几个入口:
make quick 格式与静态规则 + 不依赖 PostgreSQL/浏览器的快速测试make test 非浏览器测试 + 覆盖率门槛make check Ruff + 格式 + mypy + 迁移漂移 + Django 系统检查make e2e-chromium 当前机器可执行的 Chromium 浏览器验证make e2e Chromium + WebKit 完整浏览器验证make bugfix TEST=... 针对一个失败场景的最小复现HARNESS.md 不只是复制命令,还要记录运行条件。例如 make e2e 当前需要主机额外安装 WebKit 系统库,涉及行锁的并发测试需要真实 PostgreSQL。
统一入口的价值不是少敲几个字符,而是让人和 AI 对“快速验证”“完整验证”说的是同一件事。
5. 覆盖率门槛也会暴露设计问题
最初的快速测试全部通过,但运行带覆盖率的测试时失败了:
15 passedcoverage: 70.69%required: 80%这次失败不能简单地把门槛从 80% 改成 70%。先看缺失行,发现两类问题:
ASGI、WSGI 和不同环境设置等启动壳被算入业务覆盖; 数据库地址解析和通知 Worker 的可观察行为缺少测试。
修正时分别处理:
从覆盖统计排除没有业务分支的启动配置; 增加 PostgreSQL 地址解析、错误协议、缺少主机、凭据解码测试; 增加 Worker 单次空轮询测试; 增加低多样性生产密钥的拒绝测试。
最终结果是:
21 tests passedbranch coverage: 94.77%覆盖率不是质量分数,但一次失败帮助我们发现了真正缺少验证的配置路径。正确做法是解释数字背后的代码,而不是只追求仪表盘变绿。
6. 生产配置应该尽早失败
开发环境常常会提供宽松默认值,生产环境不能这样做。
邻行的生产配置要求以下信息显式存在:
Django 密钥; 允许域名与 CSRF 可信来源; PostgreSQL 地址; 敏感字段密钥及当前版本; 网站公开地址。
缺少任何一项都会在设置加载阶段报错。密钥不仅要求长度至少 50 个字符,还拒绝由同一个字符重复组成的低多样性值。
在一组临时、非真实凭据下执行 Django 的生产部署检查,结果为零警告。
这里验证的是配置规则,不代表服务器已经部署,更不代表示例密钥可以用于生产。
7. 假时钟与假渠道为什么现在就需要
邻行的核心规则大量依赖时间:默认 15 分钟窗口、截止、过期、反馈期限和提醒摘要。
如果业务代码直接到处读取当前系统时间,测试只能碰运气或真实等待。V0 因此先定义可注入时钟:生产使用系统时钟,测试使用固定的带时区时刻。
第三方提醒也一样。
Gate A 已经证明喵提醒真实接口可用,但常规测试不应该重复访问它,更不能把真实喵码放进仓库。假提醒渠道只接收相同结构的消息并记录结果,让业务任务可以测试“应该发给谁、生成什么事件”,而不是真的发微信。
真实 HTTP 适配器和失败重试会在后续提醒任务实现。
8. 浏览器通过不等于所有浏览器都通过
V0 创建了最小 Playwright 冒烟测试:启动 Django 测试服务器,用真实浏览器打开主页,确认应用可访问。
Chromium 测试通过:
1 passed但当前机器的 WebKit 缺少系统动态库,安装这些库需要管理员权限。项目没有把 Chromium 结果复制成“两个浏览器都通过”,而是在 HARNESS.md 和节点检查点中保留限制。
同理,当前机器没有 Docker 和 PostgreSQL 服务。SQLite 可以让大多数快速测试运行,却不能证明 PostgreSQL 行锁和并发行为。
因此这两个结论必须分开:
工程已经具备 WebKit 与 PostgreSQL 的运行契约≠当前环境已经完成 WebKit 与 PostgreSQL 验证这种区分会一直保留到有足够环境证据为止。
9. 让仓库自己告诉下一位开发者怎样工作
V0 最后生成并校正了三份仓库级说明:
AGENTS.md:AI 修改代码时必须遵守的架构、安全和隐私边界; ARCHITECTURE.md:快速查看模块关系与核心调用链; HARNESS.md:已经实际确认的安装、运行、快速检查和完整验证命令。
项目根 README、开发看板、任务详情和节点检查点也同步到同一个事实:V0 已完成,下一项是 K1。
如果只提交代码而不更新这些入口,下一次会话仍可能把 V0 当作未开始,或者重新猜一套命令。节点收尾的作用,就是让仓库状态不依赖聊天记录。
10. 本节点交付了什么
V0 的最终证据是:
21 个快速与完整非浏览器测试通过; 分支覆盖率 94.77%; Ruff、格式检查、mypy strict、迁移漂移检查通过; Django 普通和生产部署系统检查通过; Chromium 真实浏览器冒烟通过; WebKit 与 PostgreSQL 的未验证原因被明确记录; 仓库没有真实 .env、微信号、喵码或生产凭据;所有结果只形成本地提交,没有推送。
它仍然没有实现任何 AC-01 到 AC-56 的业务验收场景。这不是遗漏,而是 V0 的边界。
11. 写在最后
测试驱动开发的第一步,不一定是某个业务按钮。
对于一个从文档开始的新项目,更可靠的第一步是先证明:环境能够复现,配置错误能够被看见,测试可以稳定替换时间和外部服务,所有人使用同一套验证入口。
这条跑道建好以后,下一篇才进入第一个真实用户闭环:社区邀请码、用户名密码登录,以及不会在普通页面和日志中泄露的微信号与喵码。
那时 TDD 要证明的不再只是“页面能打开”,而是邀请资格、会话权限、敏感资料加密和失败恢复都符合已经批准的产品规则。
12. 关键代码与操作
下面是生产配置失败测试的简化摘录。它只展示验证方法,省略了项目内部辅助函数和导入:
deftest_production_config_rejects_short_secret_key(): environment = valid_environment() environment["DJANGO_SECRET_KEY"] = "too-short"with pytest.raises(ImproperlyConfigured, match="at least 50"): load_production_config(environment)验证命令:make bugfix TEST=tests/test_config.py::test_production_config_rejects_short_secret_key
这条测试的重点不是某个具体密钥,而是证明生产配置错误会在进程启动前被明确拒绝。
13. 本篇验证摘要
项目提供统一的环境安装、快速检查、完整测试和浏览器测试入口; 开发配置可以直接启动,生产配置缺少数据库、密钥或站点地址时会尽早失败; 健康检查分别验证进程存活和数据库可用性; 自动测试可以替换时钟和第三方渠道,不依赖真实提醒服务; 当前环境未完成 PostgreSQL 并发和 WebKit 系统依赖验证,这两项继续作为明确缺口。
14. 附录:相关工具与仓库
14.1 gstack
仓库:garrytan/gstack 地址:https://github.com/garrytan/gstack
14.2 dev-harness
仓库:Dev-Wiki/dev-harness 地址:https://github.com/Dev-Wiki/dev-harness
14.3 UI UX Pro Max Skill
仓库:nextlevelbuilder/ui-ux-pro-max-skill 地址:https://github.com/nextlevelbuilder/ui-ux-pro-max-skill
夜雨聆风