TT Lab
开始
学习 学习路径 课程

测试工具实战

把覆盖率的空白填上

在 TT Lab 中继续学习

目标

学习的不是如何编写测试,而是如何选择要测试的内容。 把覆盖率当作地图,而不是目标。

为什么重要

100% 覆盖率不能保证任何事情。仅有 assert x is not None 也能达到 100%。 相反,真正危险的部分(错误处理、边界值)因为难写测试而保持空白,bug 正因如此存活。

本实验将用数字找到这些空白并补上,最后以决定哪些地方不测试结束。

环境

pytest --cov=<모듈> --cov-report=term-missing
pytest --cov-branch      분기 커버리지
pytest --durations=5     느린 테스트 다섯 개

虽然没有网络,但镜像中已包含 pytest、coverage 和 hypothesis。

步骤

  1. 有三个分支的函数 → /root/work/tt/billing.py
  2. 只测试正常路径 → test_billing.py
  3. 确认缺失行 → /root/work/tt/03-cov.txt
  4. 补上错误路径
  5. 分支覆盖率 → /root/work/tt/05-branch.txt
  6. 使用 hypothesis 验证性质
  7. 慢测试 → /root/work/tt/07-slow.txt
  8. 决定不测试的内容 → /root/work/tt/08-verdict.md

参考

创建要测试的代码

有三个分支的函数 → /root/work/tt/billing.py

创建 /root/work/tt/billing.py。一个函数即可——discount(price, rate) 要做到:(1) rate 不在 0~1 范围时抛出 ValueError;(2) price 为负数时抛出 ValueError;(3) 其他情况返回四舍五入后的整数。三个分支很适合观察覆盖率。

第一个测试

只测试正常路径 → test_billing.py

在同一目录创建 test_billing.py,只测试一条正常路径,并用 pytest -q 使其通过。暂时不要处理错误路径——下一步让覆盖率指出它们。

查看遗漏的行

确认缺失行 → /root/work/tt/03-cov.txt

运行 pytest --cov=billing --cov-report=term-missing -q,并把结果保存到 /root/work/tt/03-cov.txt。Missing 列应显示错误处理对应的行号。答案不是覆盖率数字,而是那些行号。

补上空白

补上错误路径

为两条错误路径增加测试,使用 pytest.raises(ValueError)。再次测量时,覆盖率应达到 100%。

分支覆盖率并不相同

分支覆盖率 → /root/work/tt/05-branch.txt

用 pytest --cov=billing --cov-branch --cov-report=term-missing -q 重新测量,并保存到 /root/work/tt/05-branch.txt。即使行覆盖率是 100%,分支覆盖率也可能不是 100%——目标就是看清这个差异。

人想不到的输入

用 hypothesis 验证性质

用 hypothesis 编写一个 property-based test。通过 @given(st.integers(min_value=0, max_value=10**6), st.floats(min_value=0, max_value=1)) 验证“结果始终不大于 price”等性质。区别在于写出规则,而不是罗列示例。

找出慢测试

慢测试 → /root/work/tt/07-slow.txt

用 pytest --durations=5 -q 查看最慢的五个测试,并把结果保存到 /root/work/tt/07-slow.txt。慢测试会逐渐没人运行,而不运行的测试比没有测试更糟。

决定哪些内容不测试

决定不测试的内容 → /root/work/tt/08-verdict.md

在 /root/work/tt/08-verdict.md 中写三行:(1) 本模块必须测试的内容;(2) 决定不测试的内容;(3) 原因。本实验的结论是不把 100% 当作目标。