1.测试精准度
测试精准度,就是执行的测试用例覆盖了多少的测试需求。
需求覆盖率和代码覆盖率 两个维度
举个例子,新版本有10个需求,执行的测试用例覆盖了8个需求,以需求覆盖来评定,它的测试精准度就是80%。
2.代码覆盖率的度量方式
代码覆盖率(code coverage)是用来衡量代码被覆盖程度的一种度量方式。它最初是白盒测试的一个指标,现在被广泛应用于系统测试领域。
代码覆盖率的度量方式:
(1)语句覆盖 (Statement Coverage)
又叫行覆盖,度量被测代码中每个可执行语句是否执行到了。
例子:
int foo(int a,int b){
return a/b;
}
如果我们设计了这样一组用例:
Tc:a=1,b=3
很明显语句覆盖达到了100%,语句覆盖虽然达到了100%,却没有发现最简单的bug:b=0时会抛出一个除零异常。所以这个语句覆盖不是很靠谱,常常被人指责为“最弱的覆盖”,它只管覆盖代码中的执行语句,却不考虑各种分支的组合。
(2)判定覆盖(Decision Coverage)
度量程序中没一个判定的分支是否都被测试到了。例子:
int foo(int a,int b) {
if(a<10 || b<10) { //判定
return 0; //分支1
} else {
return 1; //分支2
}
}
设计判定覆盖案例时,我们只需要考虑判定结果为true和false两种情况,因此,设计如下的案例就能达到判定覆盖率100%:
Tc1:a=5,b=任意数字 覆盖率分支1
Tc2:a=15,b=15 覆盖率分支2
(3)条件覆盖(Condition Coverage)
度量判定每个子表达式结果true和false是否被测试到了。
int foo(int a,int b) {
if(a<10 || b<10) { //判定
return 0; //分支1
} else {
return 1; //分支2
}
}
设计条件覆盖案例实,我们需要考虑判定中的每个条件表达式的结果,为了覆盖率达到100%,设计了如下的案例:
Tc1:a=5,b=5 true true
Tc2:a=15,b=15 false false
通过上面的例子,我么应该很清楚判定覆盖和条件覆盖的区别。需要特别注意的是:条件覆盖不是将判定中的每个条件表达式的结果进行排列组合,而是只要每个表达式的结果true和false都测试到了就行了。因此我们可以这样推论:完全的条件覆盖并不能保证完全的判定覆盖。上面的例子虽然完整的做到了条件覆盖,但是却没有做到完整的判定覆盖,只覆盖了分支1。
从上面的例子可以看出这两种覆盖方式看起来似乎都不如听上去的那么完美。
(4)路径覆盖(Path Coverage)
路径覆盖式度量函数的每一个分支是否都被执行到。路径覆盖会随着分支的数量指数级别的增加。
int foo(int a,int b) {
int nReturn = 0 ;
if(a<10){ //分支1
nReturn +=1;
}
if(b<10) { //分支2
nReturn +=10;
}
return nReturn;
}
被测代码中nReturn的结果一共有四种可能的返回值:0,1,10,11;而上面针对每种覆盖率设计的测试案例只覆盖了部分返回值,以下针对路径覆盖设计出来的测试用例:
tc1: a=5,b=5 nReturn =11;
tc2: a=15,b=5 nReturn =10;
tc3: a=5,b=15 nReturn =1;
tc4: a=15,b=15 nReturn =0;
以上测试用例路径覆盖率100%。路径覆盖率将所有可能的返回值都测试到了,被认为是“最强覆盖”。
3.如果度量代码覆盖率?
项目共有10万行代码。执行测试用例,测试覆盖了8万行,那么8/10 = 80% 就是本次测试的代码覆盖率。
代码覆盖率分: 全量代码覆盖率和增量代码覆盖率 (差异化代码覆盖 也叫增量代码覆盖)
精准测试过程
测试分析:通过差异化的测试分析得到测试范围集合
测试执行:手工执行用例
代码覆盖率统计:工具自动手机
覆盖率结果分析: 需要【人工分析】
反馈调整:根据分析的结果,对于应覆盖但未覆盖 到的代码,需要补充用例;对于无需覆盖的代码,记录下来,为下次做参考
代码覆盖率结果分析参考模式
(1)try/catch类
示例:
try{
//代码区
} catch(Exception e) {
//异常处理
e.printStackTrace();
}
当程序运行到异常时,try catch类才会进入catch的异常处理模块,异常处理模块一般是sdk通用的函数,不会出现问题,因此不需要特别构造异常条件来覆盖,风险可控。
(2)日志类
日志类代码一般是调系统api输出日志信息,不会出问题,风险可控。
(3)空指针判断
if(!m_bInit) {
return false;
}
(4)其他风险可控的不覆盖类型
- 预埋逻辑
- 冗余代码
- 尚未使用的公共库代码