Lecture7 结构测试 - 语句覆盖StatementCoverage

结构测试 StructuralTesting

结构测试也称为白盒测试,是基于实现或基于代码的测试
测试旨在评估程序代码的特定方面,例如语句或决策
提供实现的覆盖范围,但不提供规范的覆盖范围
通常在功能测试后使用

StatementCoverage

确保每一行代码都在测试过程中得到执行,即实现 100% 的语句覆盖率
步骤如下:
1.构建一个被测试软件的控制流图(CFG)
2.每个节点都是独立的源码语句的序列
3.CFG上的每个节点都是测试案例
4.确定覆盖每个源代码语句所需的输入值
5.使用规范(非源码)确定相应的输出

控制流图 Control Flow Graphs

控制流图CFG 是一个有向图,它通过代码段显示控制流
CFG 主要用于源代码级别
CFG 中的一个节点代表源代码中的一个或多个不可分割的语句
每条边代表控制流中的分支或跳转
一个有两个出口的例子代表了一个决定,有正确和错误的出口
CFG 是语言独立的 CFG is language independent
CFG 提供了源代码的简化模型

如果i和j是程序图中的节点,当且仅当对应于节点j的语句fragment可以在对应于节点i的语句fragment之后立即执行时,从节点i到节点j就存在一条边。

结构化程序设计 Structured Programming Constructs

If-Then-Else

if语句为单独的一个节点,为true的情况合并为一个节点,为false的情况也合并为一个节点(else)
然后在if语句段结束后的语句重新判断节点
结束部分(如右大括号)和else位于一个节点


Case Switch

Switch开头为独立的一个节点
每个case及其操作为一个节点
结束区域为单独节点
如果case无break,则最近的break为结束点

如果遇到其它复杂情况,一步步分析即可

Pre-test Loop

循环头(判断循环的地方)为一个节点
循环体内独立为一个部分,并在循环体的末尾把箭头指回开头

Post-test Loop

同理,不过把Pre-test Loop的节点首尾倒置

Decisionvs.Condition

TestCases for Statement Coverage

1.源代码中的每个语句都是测试用例
2.通常情况下,单行的源码是一个声明
3.使用控制流图来最小化测试用例的数量
4.控制流图中的每个节点都是一个测试用例

做流程图(标结点,画路径,分语句)->写测试用例,每一个Node是一个用例->画测试路径,测试路径就是之后的测试数据



Statement Coverage Summary

1.结构测试的错误和非错误案例之间没有区别
2.声明覆盖Statement Coverage 在功能测试Fnctional testing 后使用
3.在实践中,应该消除重复的测试用例
4.源代码的每一行都必须执行
5.在测试过程中,通过执行源码中的所有语句,它提供了一个最大的覆盖水平
6.语句覆盖一般需要少量的测试

Strengths And Weaknesses

1.在某些情况下,很难确定所需的输入参数值
2.它无法覆盖程序的所有逻辑,也无法生成所有可能的输出值
3.它不能为“NULL else”条件提供覆盖
4.它不会为复合逻辑条件中的单个条件的每个值生成测试用例

比如 if(passengers>= 121 || (passengers>= 81 && comfortFlag))

Lecture8 结构测试:分支覆盖Branch Coverage

简介

分支覆盖率的目标是确保源代码中的所有分支在测试期间都经过检查
即 100% 的分支覆盖率
分支覆盖也是基于控制流图的

我们使用程序的控制流图来识别参数的输入值,并使用规范计算出正确的输出

相似的,对于测试用例和测试数据:
1.在控制流程图中,源码中的每个分支都是最新的案例,也就是说,图中的每个分支都是测试案例
2.测试数据的选择是为了确保图形中的每条边都被执行
3.输出必须符合规格

实例





小结

分支覆盖确保每个决策的每个输出路径至少经过测试
100% 分支覆盖保证100% 语句覆盖
分支覆盖是比语句覆盖更强大的测试形式
它解决了“NULL-else”条件的问题
它没有考虑采取每个分支的条件,或采取不同分支的组合,也就是说它不会对判断语句中的条件进行100%覆盖

Lecture9 结构测试-条件覆盖 ConditionCoverage

简介

条件覆盖的目标是每个决定中的每个条件的情况,以获取真假值
必须使用每个条件的两个可能值(即true和false)来执行决策
建议不要考虑特定于语言的功能

1.重点是条件的结果
2.确定所需的输入参数值可能很困难
3.它并不总是能达到分支覆盖率
4.每个决定至少被要采取一次
5.每个条件的真和假都需要被测试至少一次
6.目标是实现对每项决定的100%覆盖和对每项条件的100%覆盖

覆盖所有条件(正确/错误)和决策(正确/错误),同时保持序列数最少

执行实例

我们分以下几步来执行条件覆盖测试
1.通过语句分析得到条件与测试用(有时需用到真值表)

2.通过1中的测试用例,编写测试数据

3.合理组织1中的各种测试,尽量在最小的序列的组合情况下完成所有测试

4.依据3和之前的数据,编写测试数据和预期结果

顺带一提,如果条件复杂了一点,我们也要相应的分更多情况来讨论

小结

它是涵盖条件覆盖和决策覆盖的,是一个更强的覆盖范围
每一个决定都经过测试,每一个条件都经过测试
它不会测试所有可能的条件组合,也就是说它只负责测试有哪些条件,而不关心条件之间的组合
很难确定所需的输入参数值

多条件测试 MultipleCondition Coverage

其适用于包含多个条件的决策
具有n个独立的条件的决策语句,自然会有$2^n$个的测试用例

1.同样的分析决策语句,但此时运用真值表会让分析更简单合理

2.依据1的test case 或者真值表,写出test data(此时应舍弃不可能不合理的数值)
3.编写Test Date 进行测试

同样的,如果决策语句的条件更加复杂,也同样会有更多的测试用例

多条件覆盖测试 小结

1.测试每个决策中可能的条件组合
2.每n个条件就会有$2^n$个测试用例,这会导致测试代价变高
3.在实践中,我们通常在一个决策中没有太多条件
4.可能难以确定所需的输入参数值

改进版多条件测试 Modified Condition Decision Coverage

修改的条件决策覆盖率检查每个条件对输出的独立影响
测试用例是基于普通的条件测试的,并进行了附加测试,以验证每个条件对输出独立影响
目标是实现每一个决策的全覆盖、每一个条件的全覆盖以及每一个条件对输出的影响的全覆盖

实例



改进版多条件测试 小结

比条件测试相比,有更强的覆盖率
与多条件测试相比,测试次数更少
在复杂的决策环境下比较成功,如航天航空、GUI、基于web的软件
但是不如正常的Multiple Condition Coverage彻底

Lecture10 结构测试-路径测试 Path Coverage

简介

1.路径测试,其测试的是测试期间执行从程序的进入到退出的所有可能路径
2.源码分析后,用输入数据选择触发执行每条路径
3.预期输出来自规范 Expected output sarederived from the specification
4.目标是实现对代码中每一条路径的全覆盖

执行

1.作出CFG控制流图

2.分析路径并写出Test Cases,每一条路径就是一个Test case

3.依据2的情况,写出对应的测试数据和预期结果

如何处理循环路径?

答案是利用等价类的思想处理

我们如果循环中的语句,仅仅是在迭代次数上有所不同,那么我们可以认为它们是等价的
此外,所有循环的起始点都是循环决策的那个节点,都结束与循环体末尾。也就是说,它们在结构上的区别在于内部循环时的区别
因此我们可以按照这种”区别”来把循环内部分为多个等价类,当然,如果你遇到的循环语句只是在迭代(比如把1加到5),那么实质上就只有一种路径情况

正则表达式表示

想要用正则表达式来表示控制流情况/路径情况,遵循以下原则:
1.Concatenation (点 dot .),代表的是流程中的一个步骤,在计算中被当作乘
2.Sekection(加 +),表示在控制流图中存在一个决策
3.Iteration(括号与星 ()* ),表示控制流图中的重复,也就是循环
4.如果只有if语句但没有else语句,写作(n+0)

n代表的是true的决策,0代表的是 null-else的决策

5.星号就是迭代,在等价类思想后,循环被化为0次或1次决策
所以(xxx)*可以写成 (xxx)+0

表达与计算路径数量的实例

小结

1.与Decision和Condition Coverage相比,它测试了使用其他技术无法找到的路径的组合
2.如果程序包含许多路径,则在软件测试的时候代价会变高
3.它不会明确评估每个决策中的条件
4.识别一个复杂程序中的所有路径可能会很困难