软测-第6个小时-白盒测试
32 小时通关|第 6 小时 白盒测试 总结
白盒测试:打开盒子,看程序内部代码结构、逻辑,又叫结构测试、逻辑驱动测试。和黑盒相反,黑盒不管代码,白盒研究代码。
一、白盒测试核心考点(必考)
白盒目标:覆盖代码逻辑,发现代码内部缺陷(语句错误、分支错误、路径错误) 主要测试方法:逻辑覆盖(重点!)、基本路径测试
二、逻辑覆盖(由弱→强排序,考试必背顺序)
从最低覆盖强度到最高:
- 语句覆盖:设计用例,保证每一行代码至少执行 1 次
最弱!只保证代码跑一遍,无法发现判断里面的错误 例子:
if(a>1 && b>2),只要条件为真,整行执行,就算语句覆盖;判断里面写错了都发现不了。
- 判定覆盖(分支覆盖):每个判定(if)的取真、取假都要走一次
每个 if,既要满足条件成立,也要满足不成立。 注意:只关心整个 if 结果是真 / 假,不关心 if 里面每个子条件
- 条件覆盖:判定里面每一个子条件,取真、取假都至少一次
比如
if(a>1 && b>2)子条件 1:a>1(真、假);子条件 2:b>2(真、假) ✅条件覆盖:a>1 取真、假;b>2 取真、假 ⚠坑:条件覆盖 ≠ 判定覆盖!有可能子条件真假都走到,但整个 if 判定永远全为 true 或者全 false(考试高频选择题坑)
- 判定 - 条件覆盖:同时满足【判定覆盖 + 条件覆盖】
所有判定真假都走;判定里所有子条件真假也都走。
- 条件组合覆盖(强度很高)
判定内所有子条件真假的全部组合,都覆盖一遍
if(a>1 && b>2)一共 4 种组合 ①a>1 真,b>2 真 ②a>1 真,b>2 假 ③a>1 假,b>2 真 ④a>1 假,b>2 假
- 修正的条件判定覆盖 MCC(MC/DC,高频!)
含义:在判定里,每一个子条件独立影响整个判定结果。 航空、军工软件强制要求 MC/DC。 一句话:固定其他条件不变,只改变这一个子条件,能让整体 if 结果翻转。
✅覆盖强度排序(背诵!) 语句覆盖 < 判定覆盖 < 条件覆盖 < 判定条件覆盖 < 条件组合覆盖 MC/DC 介于判定条件覆盖 和条件组合覆盖之间
三、基本路径测试法(白盒另一大方法)
- 先画程序控制流图
- 计算环形复杂度(圈复杂度),圈复杂度 = 独立路径数量 环形复杂度 3 种计算公式(计算题必考) ① 边数 - 节点数 +2 ② 判定节点数量 +1 ③ 封闭区域数 +1
圈复杂度 = 需要设计的最少独立测试路径数量
- 根据独立路径,写测试用例
四、白盒适合 / 不适合
✅适合:单元测试(最常用!单元测试大多是白盒),检查代码逻辑、分支、路径 ❌不适合:大系统整体功能测试(系统测试一般黑盒)
五、黑盒 vs 白盒 一句话区分
- 黑盒:不看代码,测功能、需求
- 白盒:看代码内部结构,测逻辑、分支、语句路径
六、背诵短句
- 白盒测试又称结构测试,检查程序内部逻辑结构,多用于单元测试。
- 逻辑覆盖强度:语句 < 判定 < 条件 < 判定条件 < 条件组合;MC/DC 独立影响判定结果。
- 基本路径法:画控制流图,计算环形复杂度,得到独立路径,设计用例。
- 环形复杂度三种计算公式。
条件组合覆盖要列出全部 4 种子条件真假组合
if (A && B) { x = 1 }
代码:if(A && B) 两个子条件 A、B,每个都有真、假,2×2=4 组
- A 真,B 真 → if 整体为真,执行 x=1 ✅
- A 真,B 假 → if 整体为假,不执行 ✅
- A 假,B 真 → if 整体为假,不执行 ✅
- A 假,B 假 → if 整体为假,不执行 ✅
你刚才漏掉了第 4 组:A 假、B 假,这是考试容易丢分的地方。
逐个覆盖简单区分(这行代码为例)
- 语句覆盖:只需要第 1 组(A 真 B 真),代码执行一次 x=1 就达标。最弱。
- 判定覆盖(分支):需要【整体 if 为真】+【整体 if 为假】 选:A 真 B 真(真),A 假 B 假(假),2 组即可。
- 条件覆盖:A 取真、A 取假;B 取真、B 取假。 比如 A 真 B 假,A 假 B 真。 ⚠️大坑!这两组:A 有真有假,B 有真有假,满足条件覆盖,但是!整个 if 判定永远都是 false,没有走到 if 里面! → 条件覆盖不一定满足判定覆盖,选择题高频坑!
- 判定条件覆盖:同时满足判定覆盖 + 条件覆盖
- 条件组合覆盖:上面 4 组全部都要测(最强的逻辑覆盖)
- MC/DC(修正判定条件覆盖) 要求:单独改变一个条件,其他不动,能让整个判定结果反转
- A&&B: ①A=T,B=T → T;改成 A=F,B=T →F (A 单独影响结果) ②A=T,B=T → T;改成 A=T,B=F →F (B 单独影响结果) MC/DC 只需要 2 组核心用例就够,不用 4 组。
一句话背强度顺序
语句覆盖 < 判定覆盖 < 条件覆盖 < 判定条件覆盖 < MC/DC < 条件组合覆盖
具体概念:
词法分析:拆单词(识别一个个最小符号,不关心句子结构)
语法分析:看句子结构(单词拼起来,符不符合语法规则)
类比中文句子:
我吃苹果词法分析:分出词语【我】【吃】【苹果】 语法分析:检查结构:主语 + 谓语 + 宾语,句子合法;如果是【吃 苹果 我】,词语都认识,但语序语法不对。
1、词法分析(Lexer 扫描)
任务:读原始字符串,去掉空格、换行,切分成记号 / Token(关键字、标识符、数字、运算符) 只识别单词,不管单词放一起合不合理。
✅例子:代码 int a = 10; 词法分析输出 Token 列表:
int→ 关键字a→ 标识符(变量名)=→ 赋值运算符10→ 数字常量;→ 分号符号
哪怕写成
10 = a int;词法分析照样能拆出:10=aint;,能识别所有单词,不会报错,它只管拆词。
2、语法分析(Parser 解析)
任务:拿上面的 Token 序列,按照语法规则,检查组合结构是否合法,生成语法树。
继续例子:
int a = 10;语法分析:符合【类型 变量名 = 常量;】语法 → 合法 ✅10 = a int;单词都没问题,但语法规则不允许数字写在等号左边,语序错误 → 语法报错 ❌
再举一个简单表达式例子 3 + 5 * 2
- 词法分析得到 Token:
3+5*2 - 语法分析:识别表达式结构,知道
*优先级高于+,构建语法树,判定表达式合法。
如果写 3 + * 5 词法:3 + * 5 (全部识别出记号) 语法:+ 后面不能直接跟 *,语法错误。
软考考点一句话背诵
- 词法分析:字符流 → Token 记号流;识别关键字、标识符、常数、运算符;最小单位是单词
- 语法分析:Token 流 → 语法树;检查语法结构、语序;最小单位是句子 / 表达式
态错误分析(软考考点,静态:不运行程序,直接读代码检查)
静态错误分析属于静态测试,不用执行代码,对源码做分析,找代码里的错误。 区分:动态测试要跑程序;静态全程不运行。
静态错误分析常见 4 类:
- 类型错误
- 引用未定义变量
- 语法错误(词法、语法错误)
- 接口 / 参数不匹配
举例 1:变量未定义(静态可查出)
int main(){
b = 10;
return 0;
}
变量b没有声明。不用运行代码,静态扫描就能发现:使用了未定义标识符。
举例 2:类型不匹配
int a = "hello";
把字符串赋值给整型变量。代码没跑,静态分析直接报类型错误。
举例 3:函数参数个数不匹配
int add(int x,int y){
return x+y;
}
int main(){
int res = add(10); //只传1个参数,函数要2个
}
不运行,静态检查发现:调用 add 参数数量不对。
举例 4:语法错误(少分号、括号不配对)
int a = 10
int b = 20;
第一行末尾缺少;。静态分析(编译器预处理阶段)直接捕获语法错误。
❗重要考点区分(选择题高频坑)
- 静态错误:代码本身语法、定义、类型问题,程序根本跑不起来,编译阶段就能发现。
- 动态错误:编译能通过,只有运行时才暴露。
背诵短句: 静态错误分析:不执行程序,检查源码,发现语法、变量、类型、参数的错误。 静态发现的错误,大多编译阶段就能拦截。
程序插桩(软考软件评测师考点)
一句话:程序插桩,就是在源代码里,手动 / 自动插入一小段额外代码(探针),用来收集程序运行信息,不改变原有业务逻辑。属于动态测试技术。
类比:给水管路上装流量计,水管(原程序)功能不变,流量计(插桩代码)统计流量。
例子
原有代码:统计两个数最大值
def max_num(x,y):
if x>y:
return x
else:
return y
插桩改造(加入探针代码)
def max_num(x,y):
# ========== 插桩代码(探针)==========
print(f"【插桩】进入函数,x={x},y={y}")
# ====================================
if x>y:
# ========== 插桩代码 ==========
print("【插桩】走if分支")
# =============================
return x
else:
# ========== 插桩代码 ==========
print("【插桩】走else分支")
# =============================
return y
插桩代码作用:
- 看走了哪个分支(判定覆盖、分支覆盖统计)
- 记录输入值、执行次数
- 统计语句有没有被执行(覆盖率)
原代码逻辑完全没变,计算最大值结果不变,只是多打印日志用来观测运行路径。
软考常考插桩用途
用来做逻辑覆盖测试(语句、判定、条件覆盖),统计代码覆盖率。
考点区分
- ✅程序插桩:动态,代码要运行;在源码加探针,采集执行信息
- ✅静态错误分析:静态,不运行代码,扫描源码找错误
考试坑题举例
【单选】程序插桩技术属于() A 静态测试技术 B 动态测试技术 答案:B
补充另一个简单 C 语言小例子
原始:
if(a>10)
s = s+1;
插桩后:
if(a>10)
{
count++; //插桩!记录这个分支被执行多少次
s = s+1;
}
count++就是插入的探针,用来统计 if 分支执行次数。
一、静态测试方法(不运行程序)
1. 代码检查法
人工 / 工具阅读源码,走查、审查,找缺陷,不执行。 例子: 团队一起评审登录函数代码,看有没有变量未初始化、注释缺失、if 判断逻辑漏洞; 比如发现代码
if(user.pwd=123456)这里用了赋值=而不是相等判断==,不用跑程序,看代码直接发现。
2. 静态结构分析法
分析程序内部结构:函数调用关系、控制流、模块接口、流程图,不运行。 例子: 工具扫描代码,画出函数调用图,发现 A 函数循环调用自己(递归无出口);或者查看模块之间参数传递类型是否匹配。只分析结构,不执行。
3. 静态质量度量法
静态计算软件质量指标,度量复杂度,不运行代码。 例子: 计算圈复杂度,算出 if、for、分支多少,判断代码好不好维护;统计代码行数、注释率、函数长度,评估代码可维护性。
二、动态测试白盒方法(必须运行程序,程序插桩常配合这两个)
1. 逻辑覆盖法(语句、判定、条件、判定条件、条件组合、路径覆盖)
设计测试用例,覆盖代码里的语句、分支、条件。 示例代码:
if a>10 and b<5:
c = c + 1
- 语句覆盖:设计用例,让这行
c=c+1执行一次 - 判定覆盖:覆盖【条件成立】和【条件不成立】两种分支
2. 基本路径测试法
基于控制流图 + 圈复杂度,导出独立基本路径,每条路径写测试用例,保证覆盖所有独立路径。 例子: 上面 if 代码,控制流图得到 2 条独立路径: 路径 1:判定为真 → 执行 c=c+1 路径 2:判定为假 → 不执行 c=c+1 给每条路径设计测试用例,覆盖全部基本路径。
✅ 考点速记(选择题)
- 静态:代码检查(找 bug)、静态结构(看调用 / 控制流)、静态质量度量(算复杂度指标),不运行
- 动态白盒:逻辑覆盖、基本路径测试,需要运行程序
坑点:圈复杂度计算本身属于静态质量度量;拿圈复杂度生成测试路径做测试,属于基本路径测试(动态)。
小选择题
下列属于静态质量度量的是? A 判定覆盖 B 计算圈复杂度 C 基本路径测试 D 程序插桩 答案:B
静态质量度量法(软考考点)
核心:不运行程序,从源码计算量化指标,评估代码质量,得到数字结果。 重点指标:圈复杂度、代码行数、注释率、函数长度、接口数量。
例子 1:圈复杂度(最常考)
源码片段:
int judge(int score)
{
if(score >=90)
return 1;
else if(score >=60)
return 2;
else
return 3;
}
静态工具直接扫描代码,算出圈复杂度:3。 含义:这个函数有 3 条独立路径;圈复杂度越高,代码越难测试、容易出错。
圈复杂度计算属于静态质量度量。 拿圈复杂度生成测试用例做基本路径测试,那一步是动态测试(区分坑点!)
例子 2:统计代码行数 & 注释率
对上面 judge 函数统计:
- 有效代码行:6 行
- 注释行:0 行
- 注释率 = 注释行数 / 总代码行 注释率太低,度量结果提示:可读性差。
例子 3:度量函数长度
如果一个函数写了 200 行代码。静态度量直接给出数值,判定函数过长,可维护性差,建议拆分。
例子 4:度量模块接口数量
统计某个模块对外暴露的函数接口有 12 个。接口过多,度量结论:模块耦合度高。
高频考题区分
- ✅静态质量度量:算出指标数字,评估质量好坏,不跑程序
- ✅静态结构分析:看结构、调用关系、画控制流图,不一定计算质量指标
- ✅代码检查法:人工 / 工具读代码,直接找 bug(比如少写 ==)
考题示例
【单选】下面属于静态质量度量的是() A. 检查函数之间调用关系 B. 计算代码圈复杂度 C. 人工审查源码发现 if 用赋值 = D. 插桩统计分支执行次数 答案:B
背诵短句:静态质量度量,是对源码做量化计算,得到指标,评估可维护性、复杂度。
静态三类汇总(背诵)
- 代码检查法:找缺陷(找 bug)
- 静态结构分析法:分析结构(调用、控制流、接口)
- 静态质量度量法:计算指标(圈复杂度、注释率、代码行数)
统一用同一段伪代码,所有覆盖都拿它举例,不容易乱:
if(A && B)
{
语句S;
}
判定:
A && B里面包含 2 个独立条件:条件 A,条件 B 语句 S:if 里面那行代码
1. 语句覆盖 SC
✅教材定义:所有语句至少执行 1 次。 只需要让 A&&B = 真,进入 if,跑一遍 S 就行。 测试用例:A=T,B=T
- 结果:S 被执行,满足语句覆盖 ⚠️缺点:完全不测试分支为假的情况。如果
&&写成||,这个用例发现不了。
2. 判定覆盖 DC(分支覆盖)
✅教材定义:每个判定,取到至少一次真、一次假。 判定A&&B要有【真】、【假】两种结果。 2 组用例:
- A=T,B=T →判定 = 真(走 if 内 S)
- A=F,B=T →判定 = 假(不走 S)
只要判定真假都走到,就满足判定覆盖。 书上原话:比语句覆盖强。 ⚠️坑:条件本身的真假不一定全部覆盖,上面例子里条件 B 永远是 T。
3. 条件覆盖 CC
✅教材定义:判定里每一个独立条件的可能取值至少出现一次。 这里两个条件 A、B。 A 要有 T、F;B 要有 T、F。 用例:
- A=T,B=F
- A=F,B=T ✅A 取 T/F;B 取 T/F,满足条件覆盖 ⚠️大坑(考试高频): 这两个用例,判定结果都是
false! 👉条件覆盖 ≠ 判定覆盖,有可能判定永远没有 true 分支。
4. 条件判定组合覆盖 CDC(判定条件覆盖)
目标:同时满足【判定覆盖】+【条件覆盖】 既要:判定取 T、F;又要每个条件 A、B 都取 T、F 用例:
- A=T,B=T →判定 = T
- A=F,B=F →判定 = F ✅A:T/F;B:T/F;判定 T/F 都有。 ⚠️缺陷:不会把条件所有排列组合全部覆盖。
5. 多条件覆盖 MCC
目标:判定内所有条件的全部组合都测一遍。 A、B 一共 4 种组合:
- A=T,B=T
- A=T,B=F
- A=F,B=T
- A=F,B=F ✅全部组合都覆盖。 缺点:条件一多,用例爆炸。3 个条件就要 8 组,4 个条件 16 组。
6. 修正判定条件覆盖 MC/DC(重点!软考高频)
要求:
- 满足判定覆盖;
- 每个条件取 T/F;
- 单独改变这一个条件,其他条件不变,就能让判定结果反转。 对于
A && B用例: - T T →真
- T F →假 (固定 A=T,B 一变,判定翻转)
- F T →假 (固定 B=T,A 一变,判定翻转)
不需要 4 组全部组合,比 MCC 用例少很多,航空、军工软件强制要求 MC/DC。
一句话强弱排序(书上顺序)
语句覆盖 < 判定覆盖 < 条件覆盖 < 判定条件覆盖 < MC/DC < 多条件覆盖
考试选择题常考坑
- 条件覆盖,不一定满足判定覆盖(刚才例子可以验证)
- MC/DC 不需要全部条件组合,MCC 才是全部组合
- 语句覆盖最弱,只保证代码行跑一遍,分支可能漏测
基本路径测试法(白盒,书上 4 个步骤 + 同一个例子)
一句话概括:基本路径测试,算出程序最少需要多少条独立路径,设计用例覆盖这一组基础路径,属于白盒测试。 适用:模块详细设计、源代码。
书上的 4 步(原文)
- 根据源码,画出控制流图
- 计算控制流图的环路复杂性 V (g)
- 找出线性无关的基本路径集合
- 写测试用例,每条基本路径都跑一遍
环路复杂性 V (g) 的含义:等于基本路径的数量,就是你最少要准备几个用例。
举简单例子
伪代码:
if(A && B)
{
S1;
}
S2;
第 1 步:画控制流图
节点: 1 开始 →2(判定 A&&B) 判定 2: ✅真 →3(执行 S1)→4(执行 S2)→结束 ❌假 →4(执行 S2)→结束
第 2 步:计算环路复杂性 V (g)(3 种计算公式,考试必考)
公式任选其一,结果一样:
V(g)=边数 − 节点数 +2V(g)=判定节点数量 +1(判定就是 if 这种分支点,最省事!)- 数封闭区域数量
这里判定节点只有 1 个(if) V(g)=1+1 =2 👉环路复杂性 = 2,最少 2 条基本路径
第 3 步:找出线性无关基本路径集合
路径 1:开始 →判定 2【真】→S1 →S2 →结束 路径 2:开始 →判定 2【假】→S2 →结束
“线性无关”:两条路线,至少有一段代码走的不一样。 不用把所有可能路径全部测完,只要这一组基础路径就行。
第 4 步:写测试用例
路径 1:A=T,B=T,走 if 里面 S1 路径 2:A=F,任意 B,不走 S1
考试重点
- 环路复杂性 = 基本路径的条数
- 公式:判定节点数量 + 1,做题最快
- 基本路径 ≠ 全部所有路径,是最小的一组独立路径
和判定覆盖对比:判定覆盖只保证判定取真假;基本路径法直接算出独立通路,生成路径用例。
再举个带两个 if 的例子巩固
if(A)
S1;
if(B)
S2;
判定节点:2 个(A、B) V (g)=2+1=3,需要 3 条基本路径。
===================================================================
白盒分为【静态白盒测试】+【动态白盒测试】(完整汇总,补上静态部分,适配 32 小时通关)
白盒测试总体分为两大类:静态白盒(不运行代码)、动态白盒(运行代码,前面咱们学的逻辑覆盖、基本路径都属于这块)
一、静态白盒测试(不执行程序,看代码 / 文档,选择题高频)
核心:不跑代码,人工或者工具分析源码
- 代码审查(同行评审):小组人工开会读代码,找缺陷。
- 静态结构分析:画控制流图、调用关系图,分析模块之间调用。
- 静态质量度量:计算环路复杂度、代码行数、注释率等指标。
- 静态错误分析
- 类型 / 语法检查(变量未定义、类型不匹配)
- 边界检查、变量引用检查(使用未初始化变量)
- 接口检查:函数入参、返回值匹配
一句话:静态白盒,只看,不运行。
二、动态白盒测试(运行代码,就是刚才那一大块)
核心:运行程序,根据代码内部控制结构设计用例
1. 白盒动态测试 4 条设计原则
- 保证模块所有独立路径至少使用一次
- 所有逻辑值,True、False 都要测试
- 在上下边界、可操作范围运行所有循环
- 检查内部数据结构,保证有效
2. 逻辑覆盖 6 种(强度由弱到强)
语句覆盖<判定覆盖<条件覆盖<判定条件覆盖<MC/DC 修正判定条件覆盖<条件组合覆盖
- 语句覆盖:所有语句至少执行一次(最弱)
- 判定覆盖:每个判定取 T、F
- 条件覆盖:判定内每个条件取 T、F(⚠️不一定满足判定覆盖)
- 判定 - 条件覆盖:判定 + 条件都覆盖
- MC/DC:每个条件能够独立改变判定结果(安全类软件常用)
- 条件组合覆盖:判定内部所有条件真假全部组合(逻辑覆盖里最强)
3. 基本路径测试法(大题考点)
4 步骤:
- 根据源码导出控制流图
- 计算环路复杂性 V (g) 公式:V (g)= 判定节点 + 1;V (g)= 边 - 节点 + 2;数封闭区域
- 找出线性无关基本路径集
- 设计测试用例,覆盖每条基本路径
V (g) 的值 = 基本路径的数量;基本路径≠全部路径
4. 其他白盒方法(单选)
- 域测试:变量定义域、边界检查
- 符号测试:符号变量代替数值做推导
- Z 路径覆盖:简化循环,循环只测 0 次、1 次
- 程序变异测试(错误驱动)
- 弱变异:执行到修改语句即可
- 强变异:执行代码,输出结果不同才算杀死变异
✅易混大坑(必背)
- 静态白盒:不运行代码,代码审查、静态分析
- 动态白盒:必须运行代码,逻辑覆盖、基本路径、Z 路径、变异测试
- 白盒≠全部是动态!静态白盒也是白盒测试!选择题最爱挖坑。
完整一句话速记
白盒分动静两类:静态只读不运行,审查代码查问题;动态跑起源代码,逻辑覆盖路径测。
浙公网安备 33010602011771号