仅仅给我数字
现在,对清单 7、8、9 的测试覆盖率的分析结果不再会使您感到惊讶。在图 4 的报告中显示我达到了 75% 的行覆盖率和 100% 的分支覆盖率。最重要的是,我执行了第 10 行!
图 4.愚弄的报酬

从第一印象看,这让我骄傲。但是这个报告有什么误导吗?只是粗略地看一看报告中的数字,会导致您相信代码是经过良好测试的。基于这一点,您也许会认为出现缺陷的风险很低。这个报告并不能帮助您确定 or 缩短操作的后半部分是一个定时炸弹!
质量测试
我不止一次地说:您可以(而且应该)使用测试覆盖工具作为您的测试过程的一部分。但是不要被覆盖报告所愚弄。关于覆盖报告您需要了解的主要事情是,覆盖报告最好用来检查哪些代码没有经过 充分的测试。当您检查覆盖报告时,找出较低的值,并了解为什么特定的代码没有经过充分的测试。知道这些以后,开发人员、管理人员以及 QA 专业人员就可以在真正需要的地方使用测试覆盖工具。通常有下列三种情况:
* 估计修改已有代码所需的时间
* 评估代码质量
* 评定功能测试
现在我可以断定对测试覆盖报告的一些使用方法会将您引入歧途,下面这些最佳实践可以使得测试覆盖报告可以真正为您所用。
1. 估计修改已有代码所需的时间
对一个开发团队而言,针对代码编写测试案例自然可以增加集体的信心。与没有相应测试案例的代码相比,经过测试的代码更容易重构、维护和增强。测试案例因为暗示了代码在测试工作中是如何 工作的,所以还可以充当内行的文档。此外,如果被测试的代码发生改变,测试案例通常也会作相应的改变,这与诸如注释和 Javadoc 这样的静态代码文档不同。
在另一方面,没有经过相应测试的代码更难于理解和安全地 修改。因此,知道代码有没有被测试,并看看实际的测试覆盖数值,可以让开发人员和管理人员更准确地预知修改已有代码所需的时间。
再次回到饮水机边上,可以更好地阐明我的观点。
市场部的 Linda:“我们想让系统在用户完成一笔交易时做 x 工作。这需要多长时间。我们的用户需要尽快实现这一功能。”
管理人员 Jeff:“让我看看,这个代码是 Joe 在几个月前编写的,需要对业务层和 UI 做一些变动。Mary 也许可以在两天内完成这项工作。”
Linda:“Joe?他是谁?”
Jeff:“哦,Joe,因为他不知道自己在干什么,所以被我解雇了。”
情况似乎有点不妙,不是吗?尽管如此,Jeff 还是将任务分配给了 Mary,Mary 也认为能够在两天内完成工作 —— 确切地说,在看到代码之前她是这么认为的。
Mary:“Joe 写这些代码时是不是睡着了?这是我所见过的最差的代码。我甚至不能确认这是 Java 代码。除非推倒重来,要不我根本没法修改。”
情况对 “饮水机” 团队不妙,不是吗?但是我们假设,如果在这个不幸的事件的当初,Jeff 和 Mary 就拥有一份测试报告,那么情况会如何呢?当 Linda 要求实现新功能时,Jeff 做的第一件事就是检查以前生成的覆盖报告。注意到需要改动的软件包几乎没有被覆盖,然后他就会与 Mary 商量。
Jeff:“Joe 编写的这个代码很差,绝大多数没经过测试。您认为要支持 Linda 所说的功能需要多长时间?”
Mary:“这个代码很混乱。我甚至都不想看到它。为什么不让 Mark 来做呢?”
Jeff:“因为 Mark 不编写测试,刚被我解雇了。我需要您测试这个代码并作一些改动。告诉我您需要多长时间。”
Mary:“我至少需要两天编写测试,然后我会重构这个代码,增加新的功能。我想总共需要四天吧。”
正如他们所说的,知识的力量是强大的。开发人员可以在试图修改代码之前 使用覆盖报告来检查代码质量。同样,管理人员可以使用覆盖数据更好地估计开发人员实际所需的时间。
2. 评估代码质量
开发人员的测试可以降低代码中存在缺陷的风险,因此现在很多开发团队在新开发和更改代码的同时需要编写单元测试。然而正如前面所提到的 Mark 一样,并不总是在编码的同时进行单元测试,因而会导致低质量代码的出现。
监控覆盖报告可以帮助开发团队迅速找出不断增长的没有 相应测试的代码。例如,在一周开始时运行覆盖报告,显示项目中一个关键的软件包的覆盖率是 70%。如果几天后,覆盖率下降到了 60%,那么您可以推断:
* 软件包的代码行增加了,但是没有为新代码编写相应的测试(或者是新增加的测试不能有效地覆盖新代码)。
* 删除了测试案例。
* 上述两种情况都发生了。
能够监控事情的发展,无疑是件好事。定期地查阅报告使得设定目标(例如获得覆盖率、维护代码行的测试案例的比例等)并监控事情的发展变得更为容易。如果您发现测试没有如期编写,您可以提前采取一些行动,例如对开发人员进行培训、指导或帮助。与其让用户 “在使用中” 发现程序缺陷(这些缺陷本应该在几个月前通过简单的测试暴露出来),或者等到管理人员发现没有编写单元测试时再感到惊讶(和愤怒),还不如采取一些预防性的措施。
使用覆盖报告来确保正确的测试是一项伟大的实践。关键是要训练有素地完成这项工作。例如,使每晚生成并查阅覆盖报告成为连续累计 过程的一部分。
3. 评定功能测试
假设覆盖报告在指出没有经过 足够测试的代码部分方面非常有效,那么质量保证人员可以使用这些数据来评定与功能测试有关的关注区域。让我们回到 “饮水机” 团队来看看 QA 的负责人 Drew 是如何评价 Joe 的代码的:
Drew 对 Jeff 说:“我们为下一个版本编写了测试案例,我们注意到很多代码没有被覆盖。那好像是与股票交易有关的代码。”
Jeff:“哦,我们在这个领域有好些问题。如果我是一个赌徒的话,我会对这个功能区域给予特别的关注。Mary 正在对这个应用程序做一些其他的修改 —— 她在编写单元测试方面做得很好,但是这个代码也太差了点。”
Drew:“是的,我正在确定工作的资源和级别,看上去我没必要那么担心了,我估计我们的团队会对股票交易模块引起足够的关注。”
知识再次显示了其强大的力量。与其他软件生命周期中的风险承担者(例如 QA)配合,您可以利用覆盖报告所提供的信息来降低风险。在上面的场景中,也许 Jeff 可以为 Drew 的团队提供一个早期的不包含 Mary 的所有修改的版本。不过无论如何,Drew 的团队都应该关注应用程序的股票交易方面,与其他具有相应单元测试的代码相比,这个地方似乎存在更大的缺陷风险。
测试有什么好处
对单元测试范例而言,测试覆盖度量工具是一个有点奇怪的组成部分。对于一个已存在的有益的过程,覆盖度量可以增加其深度和精度。然而,您应该仔细地阅读代码覆盖报告。单独的高覆盖率并不能确保代码的质量。对于减少缺陷,代码的高覆盖并不是必要条件,尽管高覆盖的代码的确更少 有缺陷。
测试覆盖度量的窍门是使用覆盖报告找出未经 测试的代码,分别在微观和宏观两个级别。通过从顶层开始分析您的代码库,以及分析单个类的覆盖,可以促进深入的覆盖测试。一旦您能够综合这些原则,您和您的组织就可以在真正需要的地方使用覆盖度量工具,例如估计一个项目所需的时间,持续监控代码质量以及促进与 QA 的协作。
