活动只剩一个名额,两位候补者却都完成了报名。我们在 5.2 批准了候补需求 R17@1.1,在 5.3 划清了界面、调度和数据对象的职责;这些产物现在需要接受检查。规格有没有遗漏?实现有没有违反规格?多个模块接起来以后,名额会不会被重复发放?软件测试围绕这些问题寻找证据。
本节沿这次自编的并发故障展开。先选观察方法,再选输入,检查代码覆盖,扩大被测范围,最后把修复送回测试。名词会分别回答这些环节中的问题。同一次活动可以同时拥有多个分类标签。
方法、阶段与目标怎样交叉
“自动化系统黑盒测试”听起来像三个方案叠在一起,其实三个词分别交代执行方式、被测范围和选例依据。一个脚本向完整报名系统发送请求,按 R17 检查结果,就可以同时符合这三个描述。把它们放进同一棵互斥分类树,反而会丢失信息。

静态与动态问被测程序是否执行。评审 R17、检查设计、用工具分析源码,可以提前发现歧义、接口不一致和未初始化引用。分析工具自己在运行,被测程序仍可没有运行,因此“用了工具”推不出动态测试。动态测试则实际执行被测对象,观察输出、状态和响应时间;被测对象也可以是解释执行的代码,并不一定先编译成独立产物。
黑盒、白盒与灰盒问设计用例依靠什么信息。按业务规格选择“满员后报名”属于黑盒思路;按代码分支选择让每个出口都走到的输入属于白盒思路。了解队列或数据库的部分内部信息,再从 API 操作系统,可采用灰盒思路。知道的信息更多,会改变设计依据,但不能据此保证某一方法查错最多。黑盒可以检查功能,也可以检查响应时间;功能测试与黑盒测试的分类依据不同。
人工与自动化问哪些活动由人执行,哪些交给工具。人工评审和自动静态分析都存在;动态测试也可以手工操作或由脚本执行。这些维度分别观察同一活动,不表示任意方法都能不加限制地填进每一种组合。
测试阶段或层次再问对象和目标:单元内部、模块集成、完整系统、交付验收。其中前三者主要扩大对象范围,验收再转向交付与使用需要,并不保证物理范围更大。功能、性能、恢复等名称说明关注内容;回归说明“修改以后再检查”的目的。回归测试可在单元、集成或系统层开展。记住每个词在回答什么,就能解释为何系统阶段仍可采用白盒信息,为何单元阶段也能按外部契约设计黑盒用例。
从一个输入到多个条件共同决定动作
先把并发问题放在一旁,检查管理员设置名额上限的接口。这里另设一条明确的教学规格:上限 L 必须是 1~100 的整数,含两端。等价类划分把输入分成预期处理方式相近的区域:合法整数、低于 1、高于 100、非整数等。用某个代表值测试一个区域,依靠的是“该区域内相关处理相近”的假设,实际仍需检查划分是否合理。
有效等价类可以在条件允许时用较少用例覆盖;无效输入常分开测试,以便识别失败原因。把非法日期、超限名额和无资格账户同时塞进一个请求,系统可能在第一个错误处就返回,另外两个检查根本没机会执行。这是一条有用的选例策略,不能扩大成“每道测试都只准一个无效字段”的普遍禁令。
边界值分析把目光移到容易写错的比较符号。步长为 1、闭区间 [1,100] 时,两端及邻值是 0、1、2、99、100、101。若改成整数开区间 (1,100),实际合法范围就成了 2~99,相邻取值随之改变为 1、2、3、98、99、100。连续量、日期精度或不同步长会带来另一组邻值。边界也可以来自输出范围;不能只记住“给输入加一减一”。

候补处理要同时考虑资格与名额,单个输入的边界已经不够。判定表将条件和动作分开:资格不合格则拒绝;资格合格且有名额则确认;资格合格但无名额则候补。一列代表一条规则。条件桩列出条件名称,条件项填取值;动作桩列出动作名称,动作项说明该规则触发哪些动作。若某条件不影响一条规则,可以标成无关项,合并时要保持原有动作含义。
因果图先把输入条件到输出动作的逻辑画出来,再可转换成判定表选例。除了与、或、非,还要表达条件约束:E 表示至多一个成立,I 表示至少一个成立,O 表示恰好一个成立,R 表示一个条件要求另一个条件;M 约束输出的屏蔽关系。写在不同位置的约束管不同对象,不能把“包含 I”理解为一个软件模块包含另一个模块。
当配置因素很多时,另一个困难出现了:组合数量增加。另设浏览器、设备、网络三个因素,每项两个水平,分别记作 A、B、C 的 0/1,假定组合都可行。全组合是 8 行;正交表 L4(2³) 可以取 000、011、101、110 四行。任意抽出两列,00、01、10、11 恰好各出现一次;三列联合仍漏掉 001、010、100、111。
| 用例 | A 浏览器 | B 设备 | C 网络 |
|---|---|---|---|
| 1 | 0 | 0 | 0 |
| 2 | 0 | 1 | 1 |
| 3 | 1 | 0 | 1 |
| 4 | 1 | 1 | 0 |
这张表用四次试验实现了明确的两两覆盖目标,保留了均衡组合。若某缺陷需要三个特定水平同时出现,它可能漏检;若某组合在环境中不可实现,也要重新安排。正交试验不能保证最高查错率。先问需要覆盖几阶交互,再判断这次删减是否可接受。
用反例读懂覆盖关系
现在打开派发逻辑,设一个独立的教学实验:D=A∧B,A 表示资格合格,B 表示有可用名额。本实验两条件都实际求值,采用非短路与,四种组合都可行,真假分支内各有可执行动作。真值表为 TT→真,其余 TF、FT、FF→假。覆盖关系必须放在这些条件下讨论。

先跑 {TF,FT}。A、B 各自都出现了真与假,因此条件覆盖达成;D 却两次都是假,确认并扣减名额的真分支一次也没运行。由此可以直接否定“条件覆盖必定包含判定覆盖”,也能否定“条件覆盖必定包含语句覆盖”。
再换 {TT,FT}。D 出现了真与假,满足判定覆盖;B 两次都是真,条件覆盖没有达成。最后换成 {TT,FF},D 与两个条件都取遍真假,达到判定/条件覆盖;但 TF、FT 两种组合没有出现,条件组合覆盖仍未达成。只改输入集合,判断就会变化。
六个常见准则各自统计不同对象。语句覆盖要求每个可执行语句执行过;判定覆盖要求每个判定的真假出口走过;条件覆盖要求每个原子条件实际取过真与假;判定/条件覆盖同时满足后两项;条件组合覆盖检查单个判定内部的条件组合;路径覆盖检查控制流图中入口到出口的路径。基路径则选取线性独立的一组路径,不能用“独立路径”替换全路径的定义。
在本节的完整求值、组合与目标可行的条件下,条件组合覆盖推出判定/条件覆盖,再分出判定覆盖和条件覆盖;判定覆盖可推出语句覆盖。条件覆盖与判定覆盖互不包含。粗粒度 CFG 若把 A∧B 作为一个判定节点,全路径只保证该节点的出口走过,不能因此声称四个内部条件组合都出现。反过来,各个判定分别遍历内部组合,也不能保证多个判定联合形成的每条全局路径都走过。
换成短路表达式 A && B,当 A 为假时,B 所在条件出现位置不会被执行。即便提前给变量 B 赋了真,也不能将这次运行算成该条件实际取真。覆盖报告采用的条件定义、控制流图粒度与求值语义必须一致,不能拿完整求值的表去解释短路执行记录。
再加现实约束:同一 x 的两个条件 x>0 与 x<0 不可能同时为真,不能捏造 TT 输入;无界循环会形成无限多条路径。无法达到的覆盖目标要解释原因。即使达到所选目标,若预期结果写错或没有检查名额计数,执行过错误赋值也可能判为通过。覆盖率提供结构证据,不能单独证明正确性。
白盒还会观察别的结构。数据流测试关注变量从定义到使用的链及异常;看到了变量名字,并不等于完成了这种测试。变异测试有意作小幅代码变化,再检查原有用例能否区分变异后的行为;判错输出就能识别变异,并不要求程序崩溃。相关学习材料中的静态分析扩展还区分控制流、数据使用、接口、表达式和信息流等观察重点,当前教材未详列这五项。信息流分析可研究输入输出之间的依赖,也可用于安全分析;这些名称不构成必须依次执行的五道工序。
圈复杂度:先固定图,再算
参考试题的流程图缺失,无法核验其标注数值。本节另画一个完整、可核对的嵌套流程:先查资格,不合格直接拒绝;合格才检查名额,有名额确认,否则候补。这与前面的单个非短路复合判定是两个模型,不能混用节点数量。
节点是开始 S、资格判定 D1、名额判定 D2、拒绝 R、确认 C、候补 W、结束 E,共 n=7。八条边是 S→D1,D1→D2/R,D2→C/W,R/C/W→E,共 边数 e=8。这里特意用小写 e 表示边数,与结束节点 E 区分;题目使用大写 E、N 时,仍按题中定义识别它们。

对于这里单连通、单入口单出口的模块 CFG,圈复杂度 V(G)=e−n+2=8−7+2=3,它是无物理单位的结构计数。若加入一条出口到入口的虚拟边使图强连通,边数先增为 9,再用相应的 9−7+1,结果仍是 3。不能加了虚拟边却又沿用未加边的计数公式。
两个判定均为二分叉,另一算法是判定节点数+1=2+1=3。三出口节点的贡献为出口数减一,即 2,不能仍按一个二分叉处理。若题目用平面区域计数,要包括外部区域,并确认交叉线是否构成真实节点;本节主要用边、节点与判定两种计数交叉核验。
本图的三条路径分别是 S→D1→R→E、S→D1→D2→C→E、S→D1→D2→W→E,各可行,组成基路径集合。圈复杂度刻画线性独立路径数量。本图总路径数也为 3,但两个顺序执行的独立二分叉判定就有四条组合路径,V 仍为 3。有循环时差异更大。跑够 V 个任意用例不会自动覆盖基路径,更不能证明无错;常见复杂度阈值是管理与审查线索,不能单凭 V>10 推出缺陷率必定指数增加。
范围扩大以后,依据和替身怎样变化
单个资格函数检查正确,不代表队列与库存协作正确。教材开头按单元、集成、系统三阶段概括,再在系统测试种类中列出验收,随后单独展开验收这一交付前测试。复习时可按常用的单元、集成、系统、验收四层组织:前三层从模块内部走向完整系统,验收转向用户交付与认可。四层是便于比较的组织口径,保留教材的对应关系。各层可在增量或迭代中重复开展,测试设计也可提前;这并非只能完成前一层全部测试后才准开始后一层的日历。
| 层次 | 主要检查对象 | 直接设计依据 | 常见分工 |
|---|---|---|---|
| 单元 | 函数、类、模块内部逻辑与数据 | 详细设计、源码;也可依接口契约 | 通常由开发者负责 |
| 集成 | 模块接口与协作 | 概要设计、接口与架构安排 | 开发与测试协作 |
| 系统 | 组装后的完整系统 | 软件需求规格说明书 | 通常由独立测试人员组织 |
| 验收 | 交付物对实际使用需求的适合性 | 用户需求、合同及验收标准 | 用户或业务代表参与、认可 |
表中的“通常”和“主要”有作用。需求规格也能为单元选例提供背景,但问直接的详细依据,详细设计更贴近;系统测试通常以黑盒方式组织,却不排斥内部信息。开发者负责单元测试也不禁止测试人员协助。题目改变的是依据还是方法、责任还是对象,要分别判断。
上层界面未完成,怎样启动已经写好的候补调度?写一个驱动 Driver模拟上层调用。调度写好了,下层库存服务尚未完成,怎样让调度继续?写一个桩 Stub代替被调用的下层依赖。调用方向始终是“驱动→被测模块→桩”。同一次测试上下两端都缺失,就可以同时需要两者。
自顶向下先接通高层控制,尚缺低层服务,常需要桩;自底向上先组合低层单元,高层调用者未就绪,常需要驱动。混合策略可以同时使用。Mock 还可检查预期交互,例如库存接口被调用几次、参数是否正确;Stub 通常提供预设响应。替身的职责需要看实际行为,名称并不能代替接口契约。
相关学习材料还把面向对象测试从方法、类、类树展开,当前教材本节未详列这组技术。方法测试可考虑等价类、组合功能、递归和多态消息;类测试关注不变量、边界与模态/非模态行为;类树测试考虑多态服务和继承关系的扁平化。方法层可以检查一次确认调用的参数与结果;类层还要检查候补→确认→取消这类调用序列是否合法;继承树层则把继承与重写的服务纳入相应子类的测试范围,检查替换后的行为。它们细分 OO 对象和技术,没有新增三个与单元、系统平行的生命周期阶段。相关替换条件可回看 5.3 的面向对象原则。
性能内容、用户参与与发布方式分开读
并发请求才可能触发重复派发。这里另定一个教学指标:200 个并发请求下,95% 的响应时间不超过 2 秒。并发数说明同一时刻的负载;200 不是每秒吞吐量,也不是在线账户总数。活动限额 100 是业务规则,更不能与服务承载能力交换使用。性能评价还要看吞吐、错误率和资源,测量时固定环境与工作负载条件。
负载测试观察指定负载及其变化下的表现;压力测试可施加超出正常范围的负载,也可减少可用资源,观察极限、退化与恢复;容量测试问满足既定服务目标时能够承受多少工作量。一些旧题将受限资源测试称为“强度测试”,另一些材料把 Stress 也译为“强度”。遇到题目要读条件及来源口径,不能据此构造一套彼此绝对互斥的四类术语。
恢复测试检查故障以后恢复服务与数据的能力;可靠性测试观察规定条件与期间内的失效表现。RTO 是恢复时间目标,RPO 是可容忍的数据恢复点/损失窗口;二者并非可靠性概率。易用性 Usability关注用户完成任务的体验,可用性 Availability关注服务可供使用的程度;中文只差一个字,测量对象却不同。
Alpha常在开发方环境由用户代表等试用,Beta常在用户实际环境试用。用户参加的测试不一定都叫验收,内部测试、Alpha、Beta、验收也不是每个项目必走的四级阶梯。A/B在同一时期把组成相似的受众随机分配到方案组,比较效果;金丝雀发布先让少量范围使用新版本,控制扩大发布的风险。一个版本可先金丝雀发布,再在其中开展 A/B 实验,两个名称各自回答不同问题。
系统内容还包括安装与反安装、用户界面、健壮性和安全性。在规定环境中检查依赖安装、升级及卸载,是完整系统可交付的测试;模拟非法输入或故障,检查健壮性;尝试越权修改候补顺序,检查安全要求。安装测试是内容目标,路径覆盖是按内部结构设计用例的技术,二者不能互相替代。
Web 测试还要从完整操作看结果。链接测试检查目标、存在性与导航关系,不要求所有内部页面都向公众开放。表单测试要检查默认值、约束、提交、服务端校验与实际保存反馈。页面显示“成功”,数据库未保存报名,仍然违反预期;只点过按钮不能证明完成整个表单用例。
发现失败之后,把修复送回证据链
回到名额超发:动态测试先记录“两次成功、人数变成 101”的失败。随后调试调查原因。本节假设两个并发请求都读到同一个空缺,而库存更新缺少必要的原子性约束;这是教学设定,不从日志片段推断真实软件根因。开发者修改库存操作,接下来要重新检查同一并发输入,确认原故障不再复现,并测试受影响的报名、取消和候补流程。

测试提供行为与预期之间的证据,调试定位和修复缺陷。生产故障也能触发调试,并不一定先有计划测试;测试可以安排计划与预算,实际耗时仍受条件影响;调试具有探索性,也能设置预算与升级机制。不要把“测试时间固定、调试完全无法管理”当成两者定义。
修复后重测原失败,关注这个缺陷是否解决;回归检查修改是否破坏其他部分。二者可在同一次测试活动中结合,但判断目标不同。候补接口的修改可能要求重跑单元、集成和系统用例;回归因此不构成第五个测试阶段。
验证 Verification问产物是否符合规定要求;确认 Validation问产物是否适合预期使用。代码符合“候补必须每次手动刷新”的规格,仍可能不满足用户及时获知空缺的需要。早期原型就能帮助确认,验证也能检查交付产品;不能按“过程/产品”或“前期/最后”划出互斥界限。
中文“确认测试”需要再读上下文。某些教材题库用它指有效性/需求确认;ISTQB 的 Confirmation testing 专指修复后重测。本节前面的重测属于后一种。两个英文词与目标不同,不能仅凭相同中文把原题解释替换掉。
质量保证 QA侧重建立过程与提供满足质量要求的信心,例如质量计划、审计与评审规则;质量控制 QC侧重检查产物并实现具体质量要求,测试是其重要手段。两者可以在同一项目配合,也不能按岗位名称简单划分。完整管理关系在 5.7 展开;以正确性验证和统计使用测试配合的 净室过程会在下一节改变传统开发与认证的分工。
教材提到的“已发现缺陷归零”针对已知记录,不能证明潜在缺陷全部消失。项目退出准则还要约定严重程度、覆盖要求和可接受风险。这个报名系统能交付,需要规格、各层测试、修复和风险接受共同留下证据。回看每个名词时,用它所问的问题定位,再用条件和反例判断能推出什么;覆盖表、阶段表与修复流程就会各居其位。