一、静态测试技术
(一)概述
- 不运行程序代码的情况下,通过质量准则或其他准则对测试项目进行检查的测试类型,人工或工具检查。
1、代码检查
2、编码规则检查
- 软件编码规范评测:源程序文档化、数据说明、语句结构、输入和输出
3、静态分析
静态分析概述
- 不需要执行程序
控制流分析
通过生成程序的有效控制流图,分析代码
(1)控制流图绘制
- 圆圈
- 箭头(边)
- 区域
结点和箭头围成的封闭的空间就是一个区域 - 绘制
一组顺序结构:简化为一个圈
汇聚结点:分叉之后没有闭合就需要加一个空圆圈
复合条件表达式 - 顺序结构
total = total + grade;
counter =counter + 1,
i=i+ 1;
- if分支结构
if (grade >= 45)
printf( “Passed\n” );
else
printf( “Failed\n” );
printf(“%s\n”,grade>=45?“Passed\n”:“Failed\n”);
- Case多分支结构
switch(grade)
case 'A':
case 'a':
++aCount;
Break;
……
default:
++dCount;
Break;
- While循环结构
int product=2;
while(product<=1000)
product=2*product;
- DO While循环结构
int couter=l;
do{
printf(“%d”,counter);
}while(++counter<=10);
int fT(int x ,int y , int z)
{
if (y>1 && z==0) //1 //2
{
x=(int)(x/y); //3
}
if(y==2 || x>1) //4 //5
{
x=x+1; //6
}
return x; //7
}
(2)McCabe圈复杂度
- V(g)=边的数量-节点数量+2
- V(g)=判断节点数+1
- V(g)=封闭区域数+1
(3)圈度复杂性建议
- 我们采用独立路径覆盖方法时,独立路径最大的数量是几条。
(4)独立路径
- 一条路径中至少有一段路径在之前的路径中没有包含过的就是独立路径。
(5)函数调用关系图
- 扇入
当前模块被调用的次数叫做扇入;
一个模块的扇入越大,就说明当前模块在系统中被重复利用的次数就越多,说明当前模块的通用性就越强。 - 扇出
一个模块要完成其功能,需要调用其他模块的数量;
一个模块的扇出数越大,说明当前模块越复杂,一般不建议扇出数大于7。 - 扇入扇出应用
数据流分析
-
测试变量设置点和使用点之间的路径的情况,称为“定义-使用对”或“设置-使用对”。
-
通过“定义一使用对”能发现缺陷
- 所使用的变量没有被定义(未定义),严重错误
- 变量被定义,但从来没有使用(未使用),可能是编程错误
- 变量在使用之前被定义了两次(重复定义),可能是编程错误
- 撤销变量之后再使用,严重错误(考虑变量撤销情况)
- 变量被定义随后又被撤销随后又被定义,可能是编程错误(考虑变量撤销情况)
- 所撤销的变量没有被定义,可能是编程错误(考虑变量撤销情况)
- 变量撤销后又再次被撤销,可能是编程错误(考虑变量撤销情况)
接口分析
接口一致性
主要是检查接口的情况。
内容
- 形参与实参在类型、数量、维数、顺序、使用上的一致性
- 全局变量和公共数据区在使用上的一致性
表达式分析
表达式分析纠正的错误
- 在表达式中不正确地使用了括号造成错误
- 数组下标越界造成错误
- 除数为零造成错误
- 对负数开平方,或对π求正切造成错误
(二)代码检查概述
- 在编译和动态测试之前
- 快速找出软件的一些缺陷的本质(黑盒是表面)
- 能发现30%~70%左右的逻辑设计和编码的缺陷
(三)代码检查形式
1、代码审查
- 按照程序所使用的语言和编码的规范,对照已经经过评审和确认的检查单,检查相关项目的代码。
- 为了检查代码设计的一致性和标准是否按照约定标准在执行、代码的逻辑表达是否正确等
2、代码走查
- 测试组人员扮演计算机角色,沿着程序的逻辑逐步运行设计好的测试用例检查程序,查找软件的缺陷
(四)代码检查的常见项目
- 检查变量的交叉引用表
- 检查标号的交叉引用表
- 检查子程序、宏、函数
- 等价性检查
- 常量检查
- 标准检查
- 风格检查
- 比较控制流
- 选择、激活路径
- 对照程序的规格说明,比较实际的代码和期望的代码,从差异中发现问题和错误
- 补充文档
二、动态测试技术
(一)基于结构的动态测试用例设计原则
分为基于数据流和控制流两类
- 保证一个模块中的所有独立路径至少被使用一次
- 对所有逻辑值均需测试true和false
- 在上下边界及可操作范围内运行所有循环
- 检查内部数据结构以确保其有效性
(二)基于控制流设计用例
int function1(bool a,bool b,bool c)
{
int x;
x=0;
if(a&&(b||C))
{
x=1;
}
return x;
}
1、方法
(1)语句测试/语句覆盖(SC)
(a)选择足够多测试数据,使每条语句都覆盖一次。使被测试程序中每条语句至少执行一次。
(b)测试集是程序代码,测试条件是代码中可执行语句,测试覆盖项要覆盖每一条可执行的语句。
(c)测试语句:x=0;if(a&&(b||C));x=1;return x;
(d)覆盖强度不强,可能检测不了逻辑与和逻辑或写错的情况
- 测试用例
- 用例1:a=T, b= T, c=T
预期结果x=1
(2)分支测试/条件覆盖(CC)
(a)设计足够多测试用例,使程序中的每个分支都被覆盖。使每一判定语句中每个逻辑条件的可能值至少满足一次。
(b)可能检测不出逻辑与和逻辑或写错的情况
- 测试用例
- 用例1:a=T,b=T,C=T
预期结果x=1
- 用例2:a=F,b=F,C=F
预期结果x=0
(3)判定测试/判定覆盖(DC)
(a)设计足够多测试用例,使程序中的==每个判定条件的取值(T/F)==都要被覆盖。使程序中的每个判定至少获得一次“真值”或“假值”。
(b)可能检测不出逻辑与和逻辑或写错的情况
- 用例1:a=T,b=T,C=T
预期结果x=1 - 用例2:a=F,b=F,C=F,预期结果x=0
- 判定测试与分支测试区别
float changeSalary( int serviceYear,int age, float salary)
{
if(serviceYear<=5)
{
if(age>30)
{
salary *=1.2;
}
}
else
{
salary *=2.0;
}
return salary;
}
- 基本块
形如{
salary *=1.2;
}这样的就是一个基本块,指程序的一组顺序执行的语句,只有一个入口和一个出口(if是入口,}是出口)
- 100%覆盖
所有的边和判断都被覆盖,此时分支和判断无区别 - 不完全覆盖
分支测试覆盖率和判定测试覆盖率会产生差异- 测试用例:
- serviceYear=10
- age=40
- salary=5000.00
- 预期输出:10000.00
- B1→B5→ B6
- 判定覆盖率:1/4=25.00%
- 分支覆盖率:2/7=28.57%
- 测试用例:
(4)分支条件测试
(a)设计足够多测试用例,使每个判定语句的取值,以及每个判定条件的取值都被覆盖
(b)可能检测不出逻辑与和逻辑或
- 测试用例:
- 用例1:a=F,b=T,C=F,
预期结果x=0 - 用例2:a=T,b=F,C=T
预期结果x=1
- 用例1:a=F,b=T,C=F,
(5)分支条件组合测试
(a)设计足够多测试用例,使每个判断中,所有条件的各种可能组合都被覆盖
(b)n个条件有2的n次方种测试用例
(c)覆盖强度最强,但工作量比较大
- 测试用例:
- 用例1: a=F,b= F ,c=F
用例2: a=T,b=F,c= F
用例3: a=F,b=T,c=F
用例4: a=F,b=F,c=T
用例5: a=T,b=T,c=F
用例6: a=T,b=F,c=T
用例7: a=F,b=T,c=T
用例8: a=T,b=T,c=T
- 用例1: a=F,b= F ,c=F
(6)修正条件判定测试
(a)保证测试覆盖强度的基础上,减少分支条件组合覆盖测试用例的数量 的一种基于控制流的动态的测试技术。
(b)设计足够多的测试用例,来确定各个条件能够影响到包含的判定结果
(c)步骤:
- MC/DC首先要求实现分支条件覆盖在此基础上,对于每一个条件C,要求存在符合以下条件的两次计算:
- 条件C所在判定内的所有条件,除条件C外,其他条件的取值完全相同
- 条件C的取值相反
- 判定的计算结果相反
(三)基于数据流设计用例
1、数据流
- 通过选择的定义-使用的覆盖率来导出测试用例集,覆盖测试项中变量定义和使用间的路径。
2、定义-使用
(1)定义
- 给变量赋值的过程;
(2)使用
- 在程序中用到这个变量但没有给它赋值的过程。
- 分为计算使用和谓词使用。
计算使用:一个变量作为其他变量定义、或者输出的计算输入。
谓词使用:用变量作为判定条件(谓词)的结果。
3、特征集
- 基于数据流的测试中,测试特征集是被测的代码段。
4、测试条件
- 代码中的定义-使用对。
5、测试覆盖项
- 全定义测试
- 全计算使用测试
- 全谓词使用测试
- 全使用测试
- 全定义–使用路径测试
6、测试用例
(1)测试用例的覆盖率
- 执行对应测试用例所覆盖到的测试项占整个待测试项的百分比
(2)全定义测试
- 从变量定义到使用的控制流子路径
- 要求覆盖变量所有定义,要覆盖从定义到其谓词使用或计算使用的至少一个子路径
(3)全计算使用测试
- 从变量定义到该定义所有计算使用的控制流子路径
- 要求至少覆盖一次变量从定义到其计算使用的自由子路径
(4)全谓词使用测试
- 从变量定义到该定义所有谓词使用的控制子路径
- 要求至少覆盖一次变量从定义到其谓词使用的自由子路径
(5)全使用测试
- 从变量定义到该定义的所有使用的控制子路径
- 要求至少覆盖一次变量从定义到它的每个使用的自由子路径
(6)全定义–使用路径测试
- 从每个变量定义到该定义的每次使用(包括谓词使用和计算使用)的所有控制流子路径
- 要求覆盖到从每个变量定义到它的每次使用的所有无环子路径(从定义到使用的过程中,对这个变量不再做第二次定义)
全使用测试和全定义–使用路径测试的区别
例如当定义到计算使用有两条路径时,全使用只需要测试其中一条路径即可,但是全定义–使用必须把这两条路径都测试了。
7、示例
(1)定义、使用分析
(2)全定义测试:定义-使用对
(3)全定义测试:测试覆盖项
(4)全定义测试:测试用例
(5)全计算使用测试:定义-使用对
(6)全计算使用测试:测试覆盖项
(7)全计算使用测试:测试用例
(8)全谓词使用测试:定义-使用对
(9)全谓词使用测试:测试覆盖项
(10)全谓词使用测试:测试用例
(11)全使用测试:定义-使用对
(12)全使用测试:测试覆盖项
(13)全使用测试:测试用例
(14)全定义-使用测试:定义-使用对
(15)全定义-使用测试:测试覆盖项
(16)全定义-使用测试:测试用例
三、基于结构的测试辅助技术
(一)词法和语法分析
1、标号交叉引用表
2、变量交叉引用表(变量定义与引用表)
3、子程序、宏和函数表
4、等价表
5、常数表
(二)程序插桩和驱动分析
1、程序插桩技术
2、程序驱动技术
四、基于结构测试的综合策略
- 应尽量先用工具对被测软件进行静态分析
- 可采取先静态后动态的组合方式
- 覆盖率是对动态测试用例设计是否充分的监督
- 根据安全风险要求,应使用与之对应的覆盖率标准来衡量代码需要被多少测试用例进行充分测试
- 在不同的测试阶段,测试的侧重点不同
- 单元测试阶段
- 以代码检查和静态分析度量工具检查和动态测试为主
- 系统测试阶段
- 在使用编码规则检查和静态分析度量工具对代码进行扫描检查后,主要根据黑盒测试的结果,采取相应的白盒测试作为补充
- 单元测试阶段
五、测试覆盖准则
1、ESTCA覆盖准则
- 规则1(为了检测rel符号的错误)
- 对于ArelB(rel可以是<、>、=)型分支谓词
- 应适当地选择A与B的值,使得当测试执行到该分支语句时,A>B、A<B、A=B的情况分别出现一次
- 规则2(为了检查差1之类的错误)
- 对于ArelC(rel可以是<、>;A是变量,C是常量
)型分支谓词 - 当rel为<时,应适当地选择A的值,使A=C-M
- 当rel为>时,应适当地选择A的值,使A=C+MM是最小单位的正数,若A和C均为整型,则M=1
- 对于ArelC(rel可以是<、>;A是变量,C是常量
- 规则3(为了检测程序语句中的错误,如该引用变量的却引用了常量)
- 对于外部输入变量赋值,使其在每一测试用例中均有不同的值和符号,并与同一组测试用例中其他变量的值和符号不一致
2、层次LCSAJ覆盖准则
- 第一层:语句覆盖
- 第二层:分支覆盖
- 第三层:LCSAJ覆盖(即程序中的每一个LCSAJ都至少在测试中被经历过一次)
- 第四层:是两两LCSAJ覆盖(即程序中的每两个首尾相连的LCSAJ组合起来都至少在测试中被经历过一次……直到第n+2层,每n个首尾相连的LCSAJ组合起来都至少在测试中被经历过一次)
3、N-S盒图
六、真题
题目
阅读下列C程序,回答问题1至问题3,将解答填入答题纸的对应栏内。
int GetMaxDay(int year, int month){
int maxday=0; //1
if(month>=1&&month<=12){
if(month==2){
if(year%4==0){
if(year%100==0){
if(year%400==0)
maxday=29;
else
maxday=28;
}
else
maxday=29;
}
else
maxday=28;
}
else{
if(month==4||month==6||month==9||month==11)
maxday=30;
else
maxday=31;
}
}
return maxday;
}```
#### 问答
【问题1】(6分)
请针对上述C程序给出满足100%DC(判定覆盖)所需的逻辑条件。
**答案:
Month>=1&&month<=12
Month<1||month>12
Month>=1&&month<=12&&Month==2
Month>=1&&month<=12&&Month≠2
Month>=1&&month<=12&&Month==2&&Year%4==0
Month>=1&&month<=12&&Month==2&&Year%4≠0
Month>=1&&month<=12&&Month==2&&Year%4==0&&Year%100==0
Month>=1&&month<=12&&Month==2&&Year%4==0&&Year%100≠0
Month>=1&&month<=12&&Month==2&&Year%4==0&8Year%100==0&&Year%400==0
Month>=1&&month<=12&&Month==2&&Year%64==0&&Year%100==0&&Year%400≠0
Month>=1&&month<=12&&(Month==4||Month==6||Month==9||Month==11)Month>=1&&month<=12&&Month≠4&&Month ≠6&&Month≠9&&Month≠11
或者等价的表达式**
【问题2】(9分)
请画出上述程序的控制流图,并计算其环路复杂度V(G)。
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/5a824e5678b74894ab6a90475b8eb5a4.png)