在测试方法中粗略的介绍了几种测试方法。其中,白盒测试的动态分析方法中提到逻辑覆盖率测试有:语句覆盖、分支覆盖/判定覆盖、条件覆盖、条件—判定覆盖和路径覆盖。这里将详细阐述逻辑覆盖率测试。
准备知识:
可执行语句:可执行的一项操作;
真、假分支:Ture、False
操作数(Opreand)、操作符(Operator):
操作数:常量(整数、十六进制数、八进制数、实数、字符、字符串)、变量(简单类型、数组类型、记录类型、指针类型、联合等);
操作符:单一操作符、二进制操作符、条件操作符、赋值操作符等。
覆盖率
概念:覆盖率是度量测试完整性的一个手段,是测试有效性的一个度量。
计算公式:
覆盖率=(至少被执行一次的item数)/item总数
目的:评估测试的有效性,找出弱点,有目的的补充用例。
缺点:测试成本随着覆盖率的提高而增加。(在一般的测试中有个指标)
分类:
● 逻辑覆盖率(Logical Coverage),也叫代码覆盖率(Code Coverage)或结构化覆盖率,属于白盒测试的范畴。
○ 语句覆盖(Statement Coverage)率:程序中可执行语句被测试的比例。
◆ 语句覆盖率=(至少被执行一次的可执行语句的数量)/(可执行语句的总数)
◆ 它最简单的覆盖,适合用于自动化测试;
◆ 几乎所有的测试都能实现语句覆盖率100%,所以它不是测试完整性好的度量。
○ 判定覆盖(Decision Coverage)率/分支覆盖(Branch Coverage)率:程序中真、假分支被测试占的比例。
◆ 判定覆盖率=(判定结果被评价的次数)/(判定结果的总数)
◆ 它直接针对代码,容易被理解,实现判定覆盖率100%是可能的;
◆ 优于语句覆盖,但对于复合条件,两个或多个条件项的组合可能导致只有特定的分支被测到。
○ 条件覆盖(Condition Coverage)率:每个条件操作数(Operand)可能的取值被测试所占的比例。
◆ 条件覆盖率=(条件操作数值被至少执行一次的数量)/(条件操作数值的总数)
◆ 条件操作符容易被确认,有助于自动化测试;
◆ 优于判定覆盖,但不能替代判定覆盖率
○ 条件判断覆盖(Decision Condition Coverage/Branch Condition
Coverage)率:设计足够多的测试用例来满足判定覆盖率和条件覆盖率
◆ 判定条件覆盖率=(条件操作数值或判定结果至少被评价一次的数量)/(条件操作数值总数+判定结果总数)
◆ 便于自动化,优于条件覆盖和判定覆盖;
◆ 不是完整的覆盖,还应该考虑路径覆盖。
○ 路径覆盖(Path Coverage)率:设计足够多的测试用例,遍历程序的所有可能的路径
◆ 路径覆盖率=(至少被执行一次的路径数)/(总的路径数)
◆ 遇到复杂程序,循环次数多的时候,完成路径覆盖是很困难的,也没有包含判定条件覆盖。
从上面的集中逻辑覆盖测试来看,它们相互补充,尽量达到被测试程序的100%,然而我们还是要明确测试是为了尽可能找出程序中的错误。却没有一种十全十美的测试方法来发现所有的错误,这也体现了测试的局限性。
● 功能覆盖(Function Coverage)率,属于黑盒测试范畴。
○ 需求覆盖:
◆ 需求覆盖率=(被验证到的需求数量)/(总的需求数量)
○ 接口覆盖/入口点覆盖:使得系统的每个接口被测试到。
以上所说的覆盖率都是属于结构化覆盖率的范畴,但是在面向对象领域中却遇到挑战。
面向对象的覆盖率:关于面向对象的一些特性的测试,如:多态性、继承性、封装性等。
class Base{
public:void foo(){helper();}
void bar(){helper();}
private:virtual void helper(){...};};
class Derived:public Base{
private:virtual void helper(){...}};
对于上面那个程序,如果你测试到了Base.foo()和 Dervied.bar(),表面上看,你测试到了Base::helper()和Derived::helper()方法,达到了分支和语句,甚至路径覆盖100%。但是Base::foo()和Base::bar()他们跟Base::helper之间的接口还没有覆盖到,所以必须加强测试。
在面向对象中,上下文是设计比较多的,上下文覆盖是一种收集被测试软件如何执行数据的方法。可以应用于多态、继承和封装的特性,也可以扩展到多线程应用。
● 继承上下文覆盖(Inheritance Context Coverage):上下文内执行到的判定分支数据量占程序内判定的总数的百分比。
○ 基类的方法在其上下文空间中的执行是完全独立于基继承类的上下文空间;继承类的方法在其上下文空间中的执行也独立于其基类的上下文空间。
○ 继承上下文判定覆盖率=(累加每个上下文内执行到的判定分支数)/(上下文数+上下文内的判定分支总数)
● 基于状态的上下文覆盖(State-Base Context Coverage)
○ 基于状态的类:考虑有状态依赖行为的类。
◆ 有边界的栈:“空状态”、“半空状态”、“满状态”,“空状态”使用pop()方法就抛出异常,“满状态”使用push()方法也会抛出异常。
○ 入口点覆盖(Entry-Point Coverage)/接口点覆盖(Interface
Coverage):如上面的有边界栈的类,只测试接口的话,是无法测试边界值的时候会不会抛出异常。
○ 白盒覆盖:如判定覆盖覆盖的接口不对应于公共接口的特性。而特定的处理是覆盖不了的。
○ 基于上下文状态转移图:描述状态及其迁移路线的图。
○ 基于状态的上下文覆盖:对应于被测类对象的潜在状态。
◆ 基于状态的上下文入口点覆盖率=(累加每个状态内执行到的方法数)/(状态数*类内方法总数)
● 已定义用户上下文覆盖(User-Defined Context Coverage)
○ 基于线程的上下文覆盖:应用到维护每个线程的独立的覆盖率。
其他覆盖率(着重了解)
● 函数覆盖:函数覆盖率=(至少被执行到一次的函数数量)/(系统中函数的总数)
● 指令块覆盖(Inheruction Blocks Coverage):指令快覆盖率=(至少被执行到一次的指令块数量)/(系统中指令块总数)
其中:指令块表示函数内部一系列语句。
● 判定路径覆盖(Decision-to-Decision Paths Coverage):DDP覆盖率=(至少被执行到一次的判定路径数量)/(系统中判定路径总数)
其中:判定路径指的是从函数入口或一个判定的开始到下一个判定的开始。
● 更改条件判定覆盖(Modified Condition/Decision Coverage):为多条件测试的情况提供方便,通过分析条件判定的覆盖来增加尽量少的测试用例。
● 分支条件组合覆盖(Branch Condition Combination Coverage):分支条件组合覆盖率=(被评价到的分支条件组合数)/(分支条件组合总数)
重在组合分支条件覆盖使用的用例
● 过程到过程路径覆盖(Procedure-to-Procedure Path Coverage):针对系统级,或子系统级的。PPP覆盖率=(至少被执行到一次的PPP数量)/(系统总PPP数量)
● Z路径覆盖
● ESTCA覆盖
● LCSAJ覆盖
● ……
如何使用覆盖率
● 基本原则
○ 覆盖率不是目的,只是一种手段
○ 不可能考虑所有覆盖率的指标,也不能只考虑一种覆盖率的指标
○ 不要追求100%的覆盖率
○ 尽可能地设计提高覆盖率的用例
● 衡量覆盖率的标准
○ 可自动化性
○ 可获得性
○ 可理解性
○ 可维护性
○ 完整性
● 使用最少测试用例来达到覆盖
用N-S图来表示结构化程序中的基本控制结构:顺序型——串行操作、选择型——分支操作、重复型——循环操作。
其中:A,B,C,D,S均表示要执行的操作,P是可取真假值的谓词,Y表示真值,N表示假值。这些图形可以相互嵌套使用。
对于这些图的测试用例数:直接数执行的操作数,顺序的相乘,选择的相加。
|