游客发表
写测试代码这事儿,测试最容易被低估。代码很多人觉得测试是测试事后补的,或者干脆不写。代码我见过一个项目,测试上线前自信满满,代码结果用户一操作就崩,测试原因是代码一个边界条件没测到——那个条件写在文档第37页,没人看。测试
Python里写测试,代码工具就那么几个,测试unittest是代码标准库,pytest更顺手。测试我偏爱pytest,代码因为它报错信息像人话。测试比如你断言失败,它会告诉你左边是什么,右边是什么,差在哪。unittest有时候只给你一个"AssertionError",你得自己猜。
写测试有个心理门槛:你刚写完功能代码,觉得自己写的逻辑完美无缺,这时候让你写测试去"找茬",心里总有点别扭。但换个角度想——测试不是证明你的代码没问题,而是记录你的假设。你假设输入是整数,假设列表不为空,假设网络请求能返回。这些假设写下来,代码的意图就清楚了。
举个实在例子。我写过一个小函数,从字典里取嵌套值,比如data["user"]["address"]["city"],但中间任何一层可能缺失。第一版代码用try-except,捕获KeyError就返回None。功能没问题,但测试怎么写?你得构造一个三层嵌套的字典,分别测试每层缺失的情况。这看起来繁琐,但恰恰是测试让你意识到——函数的行为其实有五种可能,而不是一种。后来我把函数改成用.get()逐层取,测试反而更好写了,因为行为更明确。
pytest还有一个好处,fixture机制能省不少事。比如测试数据库操作,每个测试都得连接、建表、插入数据、清理。用fixture定义好setup和teardown逻辑,测试函数只管写业务断言。我见过有人用fixture管理临时文件目录,测试完自动删除,省得手动清理。
但别误解,测试不是万能的。它抓不住设计缺陷,抓不住性能问题。你测了十种输入,可能漏掉第十一种——那种只有在并发下才出现的竞态条件。所以测试代码本身也要被审视,别写那种"为了覆盖率而覆盖"的测试。我见过有人硬凑90%覆盖率,全是mock掉真实逻辑的假测试,跑起来全绿,一上线就红。
另一个常被忽略的点:测试代码的维护成本。业务代码改了,测试也得跟着改。如果测试写得烂,改起来比业务代码还痛苦,那团队就会偷偷跳过测试。我在一个项目里见过,测试文件里有一大段被注释掉的代码,没人敢删,也没人知道为什么。后来查git历史,才知道是某个老功能废弃了,但测试没清理。
所以我的建议是:测试代码要当作一等公民对待。命名清楚,结构简单,别整花活。每个测试函数只测一个行为,别搞一堆断言塞一起。失败的时候,你要能一眼看出是哪个假设不成立了。
最后说个实际感受。写测试确实慢,尤其是前期。但一旦你有了一个能跑的测试集,改代码的时候胆子就大了。重构、优化、换实现方式,跑一遍测试就知道有没有改坏。这种安全感,比任何代码审查都实在。Python的动态特性让代码灵活,也容易出错,测试就是那个兜底的网。
友情链接