📄 本篇摘要
两只眼睛看代码:黑盒测试不看内部、只喂输入验输出;白盒测试打开盖子、按内部路径设计用例。覆盖率回答【白盒测到什么程度了】——行覆盖、分支覆盖,数字越高没测到的死角越少。但要记牢:覆盖率是必要条件,不是充分条件。
一、黑盒测试:只看输入和输出
把程序当一台不透明的机器:不关心里面怎么写的,只关心给什么输入、该出什么输出。好处:
- 测试用例和实现解耦——内部重构不影响用例;
- 逼着从【使用者视角】想问题;
- 正好适合系统/验收级测试(5-4)。
短板:不知道内部结构,就不知道哪些路径漏测了——补上白盒这只眼。
二、白盒测试:沿着路径走
打开盖子,看着代码设计用例:每个 if 的两个方向都走到了吗?循环的 0 次、1 次、多次都试了吗?白盒用例直指内部分支,专抓黑盒够不到的死路。
教材里常见的标准:
- 语句覆盖:每行代码至少执行一次(最弱);
- 分支覆盖:每个判断的真假两个方向都走过(强一档);
- 条件/路径覆盖:更细的组合(最强但用例数爆炸)。
三、覆盖率:白盒的刻度尺
覆盖率=(已执行的元素数)÷(元素总数)。行覆盖 80% 意味着还有两成代码从没跑过——从没跑过的代码,就是从未验证过的代码。工具自动统计(Python 的 pytest 配 coverage 插件一行命令)。
但是——100% 覆盖率不等于没有 bug:覆盖率只说明【代码被执行过】,不说明【断言写对了】。一个 assert True 就能把覆盖率刷满而什么都没测。覆盖率用来找【漏】,不能用来证【对】。
四、动手 Demo:一行代码测出覆盖率的含义
def discount(price, is_vip):
"""会员或满 100 打八折,否则原价"""
if is_vip or price >= 100:
return price * 0.8
return price
# 黑盒视角:随便挑几个典型输入
print(discount(200, True)) # 160.0
print(discount(50, False)) # 50
# 白盒视角:分支覆盖——if 的两个方向都要走到
# 方向 1(进打折分支):discount(200, True)
# 方向 2(不进) :discount(50, False)
# 两行就 100% 行覆盖了?——再看 or 的短路:
print(discount(200, False)) # 160.0 靠价格条件进
print(discount(30, True)) # 24.0 靠会员条件进
沙箱实跑输出:
160.0
50
160.0
24.0
看到什么算成功:四个输出与注释一致。
读结果:前两个用例已达 100% 行覆盖,但 is_vip or price >= 100 这个复合条件的每种取值来源没被单独验证过——后两个用例补上。行覆盖是地板,分支覆盖才是及格线。
五、30 秒实验
把 if is_vip or price >= 100 手滑写成 if is_vip and price >= 100,重跑四个用例——第 3 个(200 元非会员)立刻输出 200 而非 160,bug 被抓。这正是一个行覆盖 100% 却能被分支测试抓住的 bug。
六、常见误区
| 误区 | 真相 |
|---|---|
| 覆盖率 100% 就稳了 | 覆盖率只统计【跑过】,不管【断言对不对】 |
| 黑盒和白盒二选一 | 互补:黑盒保视角、白盒保路径;两个都要 |
| 覆盖率是 KPI 越高越好 | 刷指标的测试比没测试更危险——虚假安全感 |
自测三问(点击展开)
1. **黑盒和白盒的分界是什么?** 答:黑盒不看内部只验输入输出,白盒看着内部代码按路径设计用例。 2. **语句覆盖和分支覆盖谁强?** 答:分支覆盖强——每个判断的真假都走到,语句覆盖可能只走了真方向。 3. **为什么 100% 覆盖率不等于没 bug?** 答:覆盖率只记录代码被执行,断言写错或缺失时照样测不出来。- ☐ 5-5 学习完成
相关笔记
- 等价划分与边值分析 —— 黑盒用例的科学挑法
- 单元测试与集成测试 —— 覆盖率工具挂在 pytest 上
- ⌨️ 编程原理 · 索引 —— 全课路线图