测试杂感:代码覆盖率的目的

Phyllis ·
更新时间:2024-09-21
· 817 次阅读

  上一篇杂感提到同事用Windbg提高代码覆盖率,我也做过相似的事情。也是临近项目结束,也是项目的发布标准对代码覆盖率有定量要求,不同的是这次的测试对象是.NET应用。这个项目应用了LINQ to SQL技术,代码中有许多ORM类。这些类是代码生成工具的产出,一个类对应数据库中的一张表,其属性(Property)对应表的字段。开发人员图方便,生成了所有表对应的类,其所有属性都支持读写(get/set)。不幸的是,这个应用只访问部分表,而且大多是只读访问。这导致这些ORM类的代码覆盖率非常低。

  当时,我可以选择修改代码覆盖率报告,手工地排除掉这些类。但是,我也是程序员,要用程序员的方式来解决这个问题。受到Windbg提高代码覆盖率的启发,我用IronPython Console加载(load)被测试程序集(assembly),实例化ORM类的对象,然后访问其属性。2分钟后,我发现这些类具备相同的模式:拥有无参数的构造函数,除了属性外没有其他成员,所以属性都是基本类型(数值、字符串、日期)。于是,我编写了一个几十行的IronPython程序来自动访问这些类和它们的属性。其核心代码如下:

1: def access_attribute(namespace):2: for name in dir(namespace):3: try:4: type_ = getattr(namespace, name)5: if type(type_) == type(System):6: access_attribute(type_)7: continue8:9: bj = type_()10: for attr in dir(obj):11: try: setattr(obj, attr, type(getattr(obj, attr))())12: except: pass13: try: setattr(obj, attr, None)14: except: ass15: try: setattr(obj, attr, ‘‘)16: except: pass17: except:18: pass

  该函数递归遍历名字空间,尝试用无参数构造函数实例化对象,然后访问对象属性。

  * 第2行:获取namespace中的元素的名称,并遍历。

  * 第4行:获取namespace中的元素,并存放在type_中。在.NET平台上,type_只可能是类或名字空间。

  * 第5~7行:如果该元素的类型与System的类型相同,则说明该元素也是名字空间,那么递归遍历该名字空间。

  * 第9行:尝试用无参数构造函数实例化type_的对象,并存放在obj中。

  * 第10~16行:遍历obj对象的成员,并尝试对其赋值。

  * 代码中出现了大量的try语句块,这保证出现异常时,整个遍历过程不会被中断。

  这个Python代码大约花了我15分钟。然后,我利用它加载程序集,从根名空间开始遍历。结果是喜人的:几分钟后,所有的ORM代码被覆盖,一些具备无参数构造函数的类也被不同程度的覆盖。代码覆盖率在值上有10%的增长(或者说,有大约10%的代码是无用的)!我倍受鼓舞,决定用两个步骤进一步完善这个程序。

  1. 用Python内省(introspection)或.NET反射来获取函数的形参列表。根据形参列表,构造实参列表,并调用函数。这样可以实例化大部分非抽象类,并调用其公有函数。

  2. 利用演化测试(evolutionary testing)来自动提高代码覆盖率。在大学的时候,我研究过演化测试,并用C++实现了一个演化测试的原型,为论文提供实验数据。现在,演化测试已经渐渐从实验室走向工业应用。微软研究院的Pex利用符号执行、演化测试等技术,可以自动生成全语句覆盖的单元测试。

  开发一个测试平台的想法确实很有吸引力,但是我不得不面对现实。15分钟提高10%确实很经济,投入几天的时间再提高10%值得么?捕获所有的异常,只管调用,不管结果,这是测试吗?获取代码覆盖率的目的是什么?设置代码覆盖率标准的目的又是什么?

  正如测试是对代码的反馈,代码覆盖率是对测试的反馈。获取代码覆盖率,不是要证明测试的充分性,而是要发现测试的遗漏,从而补充测试用例,以发现隐藏的缺陷。设置代码覆盖率标准,是提醒开发团队努力提高测试的覆盖率,以降低未发现缺陷的数目。所以,代码覆盖率是一种寻找缺陷的技术。它是提高测试的手段,不是测试的目的。只收集代码覆盖率,却不利用它去发现更多的缺陷,是误入歧途。

  在我的工作中,我总是发现我或他人错误地理解了代码覆盖率的目标,并采取了高投入、“零产出”的方法来提高代码覆盖率。这篇博文反映了技术人员的思维模式:将所有问题都转化为技术问题,然后提供技术性的解决方案,却忘却了初的目的。

  当然,我不是在暗示Pex是无用的。你研究一下,会发现Pex将技术放在一个合理的位置。它通过与程序员合作来提供高质量的解决方案:程序员提供业务逻辑验证(以前后置条件的形式),Pex利用智能算法和日趋强大的CPU来提供精悍的测试输入。所以,紧盯目标,充分发挥各种资源的优势,才能事半功倍。(以上言论仅代表作者的个人观点,不代表51Testing观点)



杂感 覆盖率 测试

需要 登录 后方可回复, 如果你还没有账号请 注册新账号
相关文章