4、覆盖率测试的局限
举一个简单的例子来说明代码覆盖率的局限。
static void Recursion (int* depth) 97 /* if depth<0, recursion will lead to division by zero */ 98 { float advance; 99 100 *depth = *depth + 1; 101 advance = 1.0/(float)(*depth - 6); /* potential division by zero */ 102 …………….. } |
在做代码覆盖率测试时,只需要一个测试用例
*depth = 10;
就可以使以上的代码覆盖率达到100%。如果只是追求高覆盖率尽快达到要求的话,就很可能漏过 *depth = 5 会导致除数为0这样的致命的错误。
当然实际的代码可能会更复杂,不会那么简单。假如GlobalFlag是一个被多个任务使用的全局变量,*depth = 10这一个测试用例可能也会让代码覆盖达到100%,但这个100%能保证下面代码中的除数不为0吗?
static void Recursion (int* depth) 97 /* if depth<0, recursion will lead to division by zero */ 98 { float advance; 99 100 *depth = *depth + 1; 101 advance = 1.0/(float)(*depth - GlobalFlag); /* potential division by zero */ 103 …………….. } |
我认为覆盖应该分为两种,一是传统意义上说的结构覆盖,即逻辑覆盖(语句覆盖、分支覆盖等)和以及基本路径覆盖,第二是数据输入覆盖。
什么是数据输入覆盖呢?就是测试用例的输入占软件所能接受的全部输入的百分比。还用以上例子来说,
int *depth能接受的全部输入为65536个(-32768到+32767)
当前测试用例输入的个数为1(*depth = 10)
这样的结果是:
语句覆盖率为100%
但输入覆盖率仅仅为1/65536(接近于0)
其实这个问题也就是软件测试的完全性的讨论。软件测试原则之一就是不可能做完全的测试。由于工作量、时间、以及资金等等的限制,传统的覆盖率测试方法无法做到完全的测试,所以就有了测试用例的优化方法,比如只使用基本路径覆盖,循环当作一次判断选择等等,采用这些方法很容易漏掉一些致命的问题。
结合其他方面,简单总结一下,就是
● 覆盖率测试可能发现不了一些与数据相关的错误
● 覆盖率测试不可能查出程序中因遗漏路径而出错
5、覆盖率测试最佳实践
● 不要特意的去做覆盖率测试,也就是说,不要以覆盖率指标为最终目的。
接触过的一些客户,因为公司的覆盖率指标100%的要求,特意的去满足覆盖率测试指标,为了测试而测试,搞得大家都很累,最后还什么都没发现。测试的最终目的是为了发现错误,时刻牢记这一点。但刚才提到的客户却忘了,到最后唯一的信念就是覆盖率,希望尽快达到指标,完成任务。这种做法偏离了软件测试的目的,走上了错误的方向,当然达不到好的效果。
● 覆盖率测试作为功能测试完整性的衡量指标之一。
建议不要特意的去做覆盖率测试。可以考虑在做功能测试的同时,顺便查看覆盖率情况。把覆盖率数值作为功能测试完整性的一个衡量指标。
● 借助于专业的工具实施覆盖率测试
没有专门的测试工具,覆盖率几乎没有办法得到。目前覆盖率测试的工具有很多,每个工具都有自己擅长的地方,这里的关键是选择适合自己应用的工具。
以上是我自己的观点总结,不一定完全准确,仅供参考。有不同意见的可以交流。
相关链接: