本节摘要:循环的速度感最终落在编辑器里:保存即跑、只跑受影响的用例、红灯三秒内出现。本节给出 watch 模式与编辑器测试集成的配置法、缩小反馈半径的技巧组合(失败优先、聚焦单测、静默输出),以及噪声治理。读完你应能把循环的体感从"停下来跑测试"变成"红绿灯自己闪"。
前两节把流水线搭好了,但循环的心跳仍在本地。心跳快不快,用一个动作衡量:**从按下保存到红灯出现,几秒?**超过十秒,注意力就开始漂移——你会顺手切去聊天窗口,回来时忘了刚才在改什么。TDD 的节律感是注意力经济:反馈越快,你越不需要"记着"自己在做什么,红灯自己会来敲门。
pytest-watch 是最轻的方案:监视文件变化,保存即跑。关键是配上一组收缩范围的参数,让它跑得又快又安静:
ptw -- -x -q --lf
三个参数各司其职:-x 失败即停(第一条红灯就是全部信息,后面的用例暂时不必跑);-q 静默输出(只有点与摘要,进度不刷屏);--lf 失败优先(上次红的用例先跑,修复验证最快)。日常循环里还有一招"聚焦单测":只跑光标下的那条用例——编辑器的测试集成或命令行的双冒号定位都行:
pytest tests/unit/test_pricing.py::test_blacklisted_user_gets_no_coupon_discount
循环的典型节奏因此变成:聚焦跑新写的那条(红)→ 写实现 → 聚焦跑(绿)→ watch 全量扫一遍(防误伤他人)→ 提交。四步里没有一步超过五秒。
主流编辑器都有 pytest 集成:测试资源管理器列出全部用例,改完保存自动重跑,红绿直接标在行号边。比起终端,它多了一层结构化的失败视图——断言的期望值与实际值并排显示,点红灯跳转用例,点用例跳转实现。对小林这样的新人,这层视图等于把 1.1 的红灯解剖图常驻在了屏幕上。终端与图形界面各有拥趸,本册不站队,只提醒一件事:两条路线跑的必须是同一套配置、同一个环境——判断"绿"的证据源只能有份,出现"终端红、侧栏绿"的分裂现场,先查解释器与工作目录,再谈别的。
配置要点两条:把解释器钉死在项目的虚拟环境(编辑器用错环境是"我这明明是绿的"的经典来源);把测试目录与标记配置指向 6.1 定下的那份配置文件,编辑器与命令行跑的是同一套规则,两处红绿才有一致的语义。
体感层面的"秒级"落到一天里长什么样,实录一段:早上小林开工,起 ptw,侧栏常驻;写新需求的测试,保存,红——失败原因正是"函数不存在",符合预期;写三行实现,保存,绿;按下重构,提取函数,保存,绿;切走看了一眼群消息,回来继续下一条。全天他没有主动"跑过测试"——红绿自己找上门。注意两个细节:其一,切走再切回的成本极低,因为测试结果在屏幕上等着,不用重建上下文;其二,全天唯一的红灯都是"该红的红",没有一次是环境抽风——这要归功于第 3 章的柱子,false alarm 清零之后,watch 才有可能常开。反馈体系是环环相扣的,编辑器这一环体验越好,说明前面几环的基础越扎实。
实录还有个常被忽略的前提:用例切得够小。watch 的秒级体感建立在单条用例毫秒级之上——如果一条测试要起两个服务等三次超时,再快的监视也只是把漫长的等待自动化。所以编辑器体验的根仍在第 1、3 章的功夫:切片薄、前提轻、依赖被替身挡住。工具是放大器,放大的是前面的基本功。
反馈半径 = 一次反馈需要跑的用例数量。半径越窄,红灯越早出现,定位越省事。按场景配对:
--lf 加 --tb=long,半径一条但信息全开。这套配对的底层逻辑还是 2.2 的节拍:不同阶段问不同的问题,就给不同宽度的证据。最常见的不匹配是写实现时开着全量跑——三百条用例里三百条绿的噪音,把唯一那条红的信号淹了。半径的选取反过来也成立:如果你发现自己在重构后经常漏红,那是半径配窄了;如果明明只有一行改动却等上两分钟才见结果,那是半径配宽了——半径跟着阶段走,别一档到底。
⚠️ watch 加并行(xdist)是经典陷阱:保存太密集时并行任务的启停开销可能比测试本身还贵,风扇狂转而红绿姗姗来迟。watch 模式建议单进程跑窄半径,全量与并行的活留给提交与流水线——还是那句话,位次:快而窄归本地,宽而重归流水线。
💡 噪声治理有个朴素标准:红灯出现时你不需要滚动屏幕找原因。做不到,就调
--tb=short、关掉无关日志、给爱刷屏的库设日志级别——信号通道是稀缺资源,别让框架日志在你和红灯之间摆摊。
watch 的两个常见故障顺手交代:保存触发了但跑得不全——多半是监视范围没含配置文件,改了 pytest 配置它没感知,重启即可;另一个是"保存到一半的文件也被跑",写大文件时被中间态的红吓一跳,用编辑器的保存节流或 watch 工具的去抖参数(保存后延迟毫秒级再跑)都能解决。小毛病不致命,却会一点点消磨对红灯的信任——红灯的可信度是团队公共资产,值得为它调好这些旋钮。
-x 失败即停、-q 静默、--lf 失败优先。