Code Coverage Best Practices

翻译自: https://testing.googleblog.com/2020/08/code-coverage-best-practices.html

我们已经花费了数十年的时间去推广各种大型软件公司的软件测试活动。我们一直倡导的一个领域就是通过使用代码测试覆盖率数据来评估风险并识别测试中的缺陷。

但是,代码覆盖率的价值一直是一个备受争议的话题,人们对此有着强烈的两极分化的看法。每当在任何一群人中提到代码覆盖率时,似乎总是引起无尽的争论。当人们安全地躲在各自的阵营里时,这往往会使谈话偏离任何有效的进展。

本文的目标就是提供一些方法,引导”两极分化”的人们找到共同点,这样就可以在此领域上取得一些进展,并且实用地使用测试覆盖率数据。我们提出了代码覆盖率的最佳实践,从而有效地让代码保持健康状态。

  • 代码覆盖率为开发人员的工作流提供了显著的好处。它不是一个完美的测试质量指标,但是它确实提供了一个合理的、客观的、工业标准的指标和可操作的数据。它不需要大量的人机交互,它普遍适用于所有产品,并且在行业中有大量的工具可供使用。你必须理解它是一种有损的和间接的指标,它把许多信息压缩成一个数字,所以它不应该是你唯一的真相来源。相反,将它与其他技术结合使用,以创建对测试工作的更全面的评估。

  • 仅靠代码覆盖率是否能减少软件缺陷,这是一个开放的研究问题,但是我们的经验表明:在提升代码覆盖率方面所付出的努力通常可以导致工程文化朝着更卓越的方向发展,从而在长期来看能够减少软件缺陷。举个例子,给予代码覆盖率高优先级的团队倾向于将测试视作一等公民,并将更强的可测试性植入到产品设计中,这样他们只花费更少的投入就可以达到测试目标。所有这些又会反向促使我们开始编写更高质量的代码(更模块化、更干净的 API 契约、更易于管理的 code review,等等)。他们也开始更多地关心项目整体的健康,以及工程和运营的卓越性。

  • 代码覆盖率高并不能保证测试质量高。专注于使数字尽可能接近 100% 会导致错误的安全感。这也可能是一种浪费,因为需要占用机器去跑测试,并且从这些需要维护的低价值测试中产生技术债务。被推送到生产环境的代码有可能是缺乏测试的错误的代码,因为:

    • a: 测试没有覆盖到特定的代码路径。这种情况很容易通过代码覆盖率分析检测到。
    • b: 测试没有覆盖到边界情况。这种情况很难甚至不可能通过代码覆盖率分析检测到。

    代码覆盖率并不能保证覆盖的行或分支已被正确地测试,它只是保证它们已被测试执行。请注意复制/粘贴(即无意义)的测试只是为了增加覆盖率,或添加实际价值不大的测试,以符合覆盖率标准。有一个能更好地评估测试质量的工具是 mutation testing

  • 但是较低的代码覆盖率确实说明了很大一部分代码是没有经过测试的。这增加了我们将不良代码推向生产环境的风险,因此应该引起注意。事实上,代码覆盖数据的很多价值不是强调覆盖了什么,而是强调没有覆盖什么。

  • 没有能适用于所有项目的 “理想代码覆盖率” 。代码的测试覆盖率级别应该取决于:

    • (a)代码的业务影响/关键性
    • (b)代码变更的频率
    • (c)代码预期的寿命有多长

    我们不能要求每个团队都有 x% 的代码覆盖率,这是由具有特定领域知识的产品所有者所做出的最佳业务决策。任何达到 x% 代码覆盖率的要求都应该伴随着基础设施的建设,以使测试更容易,例如将工具集成到开发人员工作流中。请注意,工程师可能会开始将代码覆盖率视作一个 check box,并避免将覆盖率提升到高于目标的值,即使某些代码的覆盖率应该更高。

  • 一般情况下,许多项目的代码覆盖率是比较低的; 我们应该将显著地提高代码覆盖率作为目标。虽然没有理想的代码覆盖率,但在谷歌,我们提供了 60% 可接受、75% 值得称赞和 90% 堪称典范的一般准则。然而,我们喜欢远离广泛的自上而下的授权,鼓励每个团队选择对他们的业务需求有意义的价值。

  • 我们不应该纠结于如何将 90% 的代码覆盖率提高到 95%。超过某个点后,增加代码覆盖率的收益是很低的(对数函数)。但是,我们应该采取具体的步骤来实现从 30% 到 70% 的目标,并始终确保新代码符合我们所期望的阈值。

  • 比覆盖的行数百分比数据更重要的是:人对未覆盖的实际代码行数(和行为)的判断,以及评估这种风险是否可以接受。没有被覆盖的比被覆盖的更有意义。在代码 review 的过程中,对未被测试涉及的特定代码进行务实的讨论,这比对任意目标数字的过度追求更有价值。我们发现,将代码覆盖率嵌入到代码 review 流程中可以使代码 review 更快和更容易。但并不是所有的代码都是同等重要的。例如,log.debug() 代码通常并不那么重要,所以当开发人员不仅可以看到覆盖率数字,而且可以看到作为代码 review 的一部分突出显示的每一行覆盖代码时,他们将确保最重要的代码被覆盖。

  • 对于代码覆盖率低的项目,依然可以采取具体的、渐进的步骤来改进它。接手具有糟糕的测试和糟糕的可测试性的遗留系统是令人畏缩的,你可能觉得没有权力扭转它,甚至不知道从哪里开始。但至少,你可以采用 “童子军的规则” (始终保持露营地比你发现它时干净)。随着时间的推移,逐渐地,这个项目就会到达一个健康的水位。

  • 确保频繁变更的代码被测试覆盖到。虽然整体项目的测试覆盖率目标超过 90% 可能是不值得的,但每个提交覆盖率目标达到 99% 是合理的,90% 是一个较低的阈值。我们需要确保我们的测试不会随着时间的推移而恶化。

  • 单元测试代码覆盖率只是整个测试宇宙中的一部分。集成/系统测试代码覆盖率也很重要。流水线中所有源的覆盖范围(单元和集成)的聚合视图是最重要的,因为它可以让您更全面地了解测试自动化没有执行多少代码,因为它在您的流水线中进入一个生产环境。您应该注意的一件事是,虽然单元测试在执行代码和评估代码之间具有高度相关性,但集成测试和端到端测试的一些覆盖率是偶然的(可以理解为集成测试的粒度很粗所以天然可以覆盖到很多代码)。但是结合集成测试的代码覆盖率可以帮助你避免出现错误的安全感:即那些你没有在单元测试中覆盖代码,但你认为你在集成测试中覆盖了它的代码(实际也没有)。

  • 应该对不符合代码覆盖标准的部署进行限制。团队应该讨论并决定哪种限制机制对他们来说是有意义的。然而,你应该小心,不要把它当成 checkbox,因为它可能会适得其反(为了达到指标而写的测试几乎不会产生预期的结果)。有许多可用的机制:所有代码的覆盖率阈值 vs 新代码的覆盖率阈值;对特定硬编码代码覆盖率的限制与对以前版本的限制,即忽略或关注的特定代码部分的限制。然后,作为一个团队致力于维护这些规则。违反阈值的代码应该被禁止部署到生产环境。

如果想了解更多,欢迎阅读 Coverage at Google

发布于

2022-01-08

更新于

2022-01-11

许可协议

评论