04 · 软件测试(Software Testing)

📅 预计 45 分钟 | ⭐ = 核心概念 | 📌 中英术语见文末
✍️ 配套练习:课程中心「软件工程」模块在线测验


4.1 测试不是"找茬",是"质检"

安检员看的是"会不会出事"

想象机场安检:安检员不负责造行李,也不负责修行李,他盯的是有没有危险品、有没有漏网。软件测试就是软件的"安检"——用设计好的用例去运行程序,找出程序里的错误,让缺陷在生产环境爆发之前被拦下来。

一个关键认知:测试只能证明程序有错,不能证明程序无错。测试通过了,只说明"这些用例没触发错误",不代表软件零缺陷。这就是著名的 E.W.Dijkstra 观点:测试是"证伪"的过程,不是"证实"的过程。

基本术语 ⭐:

  • 测试用例(test case):一组输入 + 预期输出 + 执行条件。
  • 缺陷 / 故障:程序行为与规格不符的地方。
  • 测试计划:测什么、怎么测、谁测、什么时候测的规划。

💡 记忆口诀:测试 = 用"最小成本"找"最多错误"。测试用例的价值 = 发现错误的能力,不是数量。

⚠️ 常见错误

  1. 以为"测试通过 = 软件没问题":测试只能证伪不能证实,这是测试理论的核心出发点。
  2. 把"开发完才测试"当正解:测试越早介入越好,缺陷发现得越晚,修复成本越高。

4.2 测试层次:从零件到整车 ⭐

逐级把关,层层放行

软件的测试像汽车出厂质检:先查每个零件,再查零件组装,再查整车路试,最后交客户试驾。这就是测试的四个层次:

层次 测什么 类比 常用方式
单元测试(unit test) 单个函数/类/模块 逐个零件质检 开发人员写,通常配合测试框架
集成测试(integration test) 模块之间的接口与协作 零件组装后测咬合 自底向上 / 自顶向下 / 大爆炸
系统测试(system test) 整个系统是否满足需求 整车路试 对照 SRS 做功能与性能测试
验收测试(acceptance test) 用户确认能否交付 客户试驾签字 用户执行真实业务场景

单元测试:由开发者自己编写,保证每个函数逻辑正确,是成本最低、发现缺陷最早的测试。常见框架如 JUnit(Java)、pytest(Python)。

集成测试的三种策略

  • 自底向上(bottom-up):先测底层模块,再逐层向上拼装。需写"驱动模块"模拟上层调用。
  • 自顶向下(top-down):先测顶层控制,再逐层向下。需写"桩模块"(stub)模拟还没实现的下层。
  • 大爆炸(big-bang):所有模块一次性组装后整体测。简单但错误定位难,适合模块较少的系统。

系统测试重点关注:功能是否齐全、性能是否达标、安全性、兼容性等,是对照需求规格说明书的全面体检。

验收测试的常见形式:α 测试(开发方环境、有用户参与)与 β 测试(真实用户环境、用户自行使用)。

💡 记忆口诀:四个层次 = 单元(零件)→ 集成(咬合)→ 系统(整车)→ 验收(试驾)。

⚠️ 常见错误

  1. 搞混层次顺序与目的:单元测内部逻辑,集成测模块接口,系统测整体需求,验收测用户满意。
  2. 把"驱动模块"和"桩模块"记反:驱动(driver)是调用被测模块的模拟上层,桩(stub)是被测模块要调用的模拟下层。自底向上需驱动,自顶向下需桩。

按测试目的划分的常见测试

除了按"层次"划分,测试还常按目的分类,这些名词在项目里高频出现:

测试 目的 类比
回归测试(regression) 修改代码后,验证没把已通过的功能改坏 装修后检查墙没被凿漏
冒烟测试(smoke) 只跑主干流程,快速判断系统"能不能开机" 新房先通电看灯亮不亮
性能测试 看系统快不快、扛不扛得住 高峰期的收银台排队情况
压力测试(stress) 超负荷运行时系统的表现与极限 让 10 倍客流涌进来测极限
安全测试 检查越权、注入、数据泄露等漏洞 请人试着撬门

回归测试尤其重要:软件改一处,可能伤及十处。现代项目靠自动化回归测试(脚本自动跑一遍所有用例)来保证"越改越稳",而不是靠人肉重复劳动。

缺陷的生命周期

测试发现的问题不会直接消失,它有一个状态流转过程:

新发现(New) → 已确认(Open) → 已修复(Fixed) → 已回归验证(Verified) → 关闭(Closed)
                                     ↘ 不是缺陷/无法复现 → 已拒绝(Rejected)

测试人员提交缺陷报告时,要写清:复现步骤、输入数据、预期结果、实际结果、严重程度、截图/日志。一份写得清楚的问题报告,能让开发十分钟定位,而不是两小时复现。


4.3 黑盒测试与白盒测试 ⭐⭐

黑盒看"输入输出",白盒看"内部逻辑"

这是测试方法论里最重要的二分。看测试者"看得见什么":

黑盒测试(black-box testing)——看不见内部,把程序当黑箱子,只关心"给定输入,输出对不对"。

  • 依据:需求规格说明书(不依赖代码)。
  • 优点:站在用户视角,不涉及代码实现。
  • 缺点:无法覆盖所有路径,可能漏掉未按需求实现的分支。
  • 方法:等价类划分、边界值分析、判定表、错误推测等。

白盒测试(white-box testing)——看得见内部,依据程序代码设计用例,检查每条语句、每个分支、每条路径是否被正确执行。

  • 依据:源代码的结构。
  • 优点:能覆盖逻辑分支,发现"需求没写但代码写错"的问题。
  • 缺点:需要读懂代码,成本高;无法验证需求本身是否正确。
  • 常见覆盖标准:语句覆盖、判定(分支)覆盖、条件覆盖、路径覆盖。

一句话:黑盒管"做对了吗"(功能符合需求),白盒管"每条路都通吗"(逻辑没有死角)。实际项目中两者结合使用,互为补充。

⚠️ 常见错误

  1. 把黑盒/白盒与"功能/性能"混淆:黑盒白盒的分界是"是否看代码内部",不是"测什么内容"。
  2. 以为白盒只测覆盖就够了:覆盖率高不代表没缺陷——白盒补逻辑盲区,黑盒验证用户需求,缺一不可。

4.4 测试用例设计:怎么选"最会暴露问题的输入"

无穷输入中挑出"代表"

测试不可能把所有输入都试一遍(输入空间通常是无限的),所以要用方法挑出最有价值、最能暴露缺陷的用例。三种最常用方法 ⭐:

① 等价类划分(equivalence partitioning)

把输入划分成若干性质相同的集合,同一集合里的输入,程序的处理行为相同,只要每个等价类取一个代表测试即可。

  • 有效等价类:合法、合理的输入。
  • 无效等价类:非法、错误、越界的输入(测试要有意识地用无效数据测程序是否健壮)。

以"年龄 1860 可注册"为例:有效等价类 = 1860;无效等价类 = <18 与 >60(各一个)。

② 边界值分析(boundary value analysis)

实践表明缺陷最常发生在边界附近——"边界值"(恰好等于、刚好超过、刚好低于边界)最值得测。以上例:测 17、18、60、61,比测 30、40 更能发现隐患。等价类划分 + 边界值分析常成对使用。

③ 判定表/因果图(decision table)

当系统行为由多个条件的组合决定时(如"会员 + 打折日 + 满减"决定最终价格),用判定表穷举条件组合,保证每种组合都有用例覆盖。

测试用例书写要素:用例编号、测试输入、执行步骤、预期输出、实际输出、是否通过。

💡 记忆口诀:等价类选"代表",边界值专攻"临界",判定表穷尽"组合"。

⚠️ 常见错误

  1. 只测有效输入:测试的价值很大程度来自无效等价类——程序必须能优雅地拒绝错误输入而不是崩溃。
  2. 忘记边界:测了 20、40、50,唯独漏了 17/18/60/61,恰恰最可能出错的地方没测。
  3. 用例没写"预期输出":没有预期结果的用例等于"走个过场",通过与否都无法判断。

自动化测试与测试驱动开发

手工测试费时费力,所以现代项目大量引入自动化测试:用脚本把用例固化下来,一键批量执行,改动代码后自动回归。常见框架如 JUnit(Java)、pytest(Python)、Selenium(Web 界面)。

与之配套的实践是测试驱动开发(TDD,见第 1 讲 XP):先写一个会失败的测试,再写最少代码让它通过,然后重构。TDD 的作用不只是产出测试,更是用测试"逼"着把需求变成可验证的规格——没有测试的代码,等于没有验收标准的交付。

记住:自动化测试的价值在于可重复、可回归、可持续;它是保障重构安全、防止"越改越乱"的护身符。


📌 双语术语表(本讲)

中文 English 记忆点
测试用例 test case 输入+预期输出
单元测试 unit test 单个模块
集成测试 integration test 模块接口
系统测试 system test 整系统对需求
验收测试 acceptance test 用户确认
驱动模块 driver 模拟上层调用者
桩模块 stub 模拟下层被调者
α 测试 alpha test 开发方环境
β 测试 beta test 用户环境
黑盒测试 black-box testing 不看内部
白盒测试 white-box testing 看内部逻辑
等价类划分 equivalence partitioning 有效/无效类
边界值分析 boundary value analysis 临界点
判定表 decision table 条件组合
语句/分支/路径覆盖 statement/branch/path coverage 白盒覆盖标准

⭐ 本讲考点清单

  1. 测试只能证伪不能证实——"测试通过"≠"程序无错"。
  2. 测试四层次:单元→集成→系统→验收;集成三策略:自底向上(驱动)、自顶向下(桩)、大爆炸。
  3. 黑盒看输入输出(依据需求),白盒看内部逻辑(依据代码);黑盒方法含等价类/边界值/判定表。
  4. 等价类分有效与无效;边界值专攻临界(17/18/60/61 式用例)。
  5. α 测试在开发方环境、β 测试在用户真实环境。
  6. 无效等价类的价值:程序要能优雅拒绝错误输入。