用边界值测试发现真实缺陷:设计原理
一句话总结
好的边界值测试能把“看似合理却有错的实现”与正确的实现区分开来。
为什么需要它
即使是只有十行的费用计算器,只要有一个边界写错,就会对每一笔订单收取错误的金额。 只确认 price(3) 等于 1050 的测试,即使折扣阈值中的 >= 被改成 >,也照样通过。 与其重复测试许多中间值,不如选取条件发生变化的“紧邻之前、恰好那一点、紧邻之后”。 本实验不读取覆盖率报告中的数字。先在正确代码上运行你写的测试,再在条件写错了一处的代码上重新运行,从而实际观察两者的差异。
工作原理
| 输入 | 契约 |
|---|---|
| 整数 0 | 0 韩元 |
| 整数 1–9 | 每件 350 韩元 |
| 整数 10–100 | 全部数量按每件 300 韩元 |
| 范围之外的整数 | ValueError |
| 非整数的值、bool | TypeError |
折扣不是只对第 10 件之后的部分生效的累进方式,而是改变全部数量的单价。 如果没有这句话就去写测试,就会围绕不同的策略争论哪个实现才是对的。 测试名称和预期金额应当体现策略的含义。
在现场相遇的样子
在 Python 中,bool 是 int 的子类,所以 isinstance(True, int) 为真。业务上能否把数量 True 当作 1 件来接受,语言并没有规定。本契约明确拒绝这种输入,因此把 bool 单独列为反例。另一方面,如果去检查实现中的变量名或 if 语句的数量,就会把行为不变的重构误认为 bug。应当观察的是输入、结果和异常。
下一项实验要做什么
依次累积八个测试:0、1、折扣之前、边界、折扣之后、最大值、负数、错误类型。 如果在正确实现上失败,先修正测试的预期值。即使在有缺陷的实现上失败,语法错误或导入错误也不算检出缺陷。必须是已执行测试中的 assertion 失败,或者出现与预期不同的运行时异常。能抓住所有这些缺陷样本,只是对所验证契约的证据,而不是“所有 bug 都不存在”的证明。
参考:pytest 入门