本节摘要:测试的价值高度依赖它好不好读——命名是把"测试到底保什么"写给未来的人看的。本节给出三套命名范式与一套目录组织规则,并演示如何把命名当成"行为规约"来写。
命名看起来只是小事,但它决定了红灯亮起时你能不能在三十秒内判断"代码错了还是铁律破了"。一条叫 test_01 的测试,红灯亮了你得翻开实现才猜它想验证什么;一条叫 test_gold_member_gets_20pct_discount 的测试,红灯本身就在告诉你答案。换句话说,命名是给红灯配的说明书。
范式不是非此即彼,要点是一个项目里统一一套,否则检索代码时等于没有约定。
第一套,条件-动作-结果,也叫 Given-When-Then 命名:把"前置 → 操作 → 期望"胶成一个可读句子。例如 Given_ValidInput_When_ProcessData_Then_ReturnsCorrectResult,读起来像一段故事。
第二套,行为-时机,倡导"应该做什么,当什么发生时":Should_ThrowException_When_InputIsNull。它把期望挂在前面,最适合声明式的风格。
第三套,方法-场景-期望,直接钉在被测方法上:CalculateDiscount_PremiumCustomer_Applies20PercentDiscount。当被测方法名本身就信息量大时,这套最高效。
| 范式 | 结构 | 示例 | 适合谁 |
|---|---|---|---|
| 条件-动作-结果 | Given 前置 · When 操作 · Then 期望 | Given_ValidInput_When_Process_Then_OK | BDD 思维团队 |
| 行为-时机 | 应做什么 · 当何时 | Should_Throw_When_Null | 声明式风格 |
| 方法-场景-期望 | 方法名 · 场景 · 期望 | CalculateDiscount_Premium_Applies20 | 方法语义明确的库 |
比句法更重要的是:每条测试的命名应该描述"业务该有的行为",而不是"实现里做了什么"。区别很大。写 test_full_flows_through_one_branch 是描述实现;写 test_user_with_negative_balance_cannot_checkout 是描述业务契约。后者在重构内部代码时不会变脆,前者却一碰实现就碎。把测试当成"活的契约文档"来命名,命名自然就对了。
背景:给订单结算写测试,团队前三个测试叫 test_1、test_2、test_3,无人看懂。
操作:改用"行为-时机"范式重命名全部用例,并把每个断言唯一的期望挂进名字。
结果:test_should_reject_checkout_when_cart_is_empty 一读就知道护的是什么业务规则,红灯出现即答案。
解读:命名成本的收窄是立竿见影的——检索测试、定位失败、新人学习三段都省时间。
变式:跨文件的项目可以再把命名格式统一成"动词_名词_条件",再配一个持续重命名的小工具,但工具是次要的,统一口径才是主菜。
def test_should_reject_checkout_when_cart_is_empty(): cart = Cart([]) assert not cart.can_checkout()
命名之外,测试还要有组织。常用的最小规则三条:测试与被测模块按镜像目录摆,方便一眼对应;一个被测单元至少一个独立测试类,互不掺和;共享的工具函数进公共的 fixture 或 conftest,而不是塞进每条测试开头。目的是让"找测试、跑测试、看结果"三步都不迷路。规模一大再补上按功能分组的收尾,避免单测和集成测试混在一个夹层里。
很多团队把"命名"和"组织"当成两件独立的事分别治理,其实它们是同一件东西的一体两面——都服务于"四十秒内让一个人看懂这条测试在保什么、它在哪"。一个常见教训是:命名已经很规范了,可测试文件还散在二十个文件夹里,检索照样靠全库搜。反过来也一样,目录摆得规整,但每条测试叫 test_helper_01,位置找到了也读不懂。真正的做法是把命名 + 目录 + 命名空间捆绑成一份团队的测试契约,一次性定下来。
这份契约不妨写进仓库根目录的 CONVENTIONS 文件,内容就三行:命名范式用哪套、目录按什么镜像、哪些词是测试名里的保留前缀(比如 test_should_ 开头代表行为式)。新成员进来照着抄三四个例子就能上道,别让他们靠猜。
最后泼一盆冷水:命名能说明"这条测试保的是哪个行为",但它说服不了别人"这个行为到底重不重要"。再长的名字,也遮不住断言本身就是"断言恒真"这类反模式(见 2.4 再回头看 2.5)。所以命名和断言要互相兜底——名字把行为讲清楚,断言把行为钉死。别指望靠一个超长命名让测试价值上车,真正决定价值的是命名背后的那条断言链是否经得起变化。
顺带提醒一句:不要太迷信"用一条超长命名概括一切"。测试名过长反而难读,读到一半眼睛就先投降。命名该承担的是"三十秒定位",不是"把整段业务逻辑塞进函数名"。细节和原因交给断言与注释,名字只负责把用户目光引到正确的地方。
有一处日常检查最见效:写作前先把"这条测试到底要证明哪个行为"用一句话写在测试名或首行注释里,再动笔。名字越是写不下去,往往越说明"这条测试该不该存在"本身就没想清楚——这正是命名纪律能在你动手前就先止损的地方,比跑出结果再去改名字省心得多。