谷歌的代码覆盖率最佳实践

为了推动软件测试的发展,我们花了几十年的时间和多家大型软件公司进行过合作。我们一直倡导大家需要使用代码覆盖率数据来评估质量风险并识别测试是否充分。然而,代码覆盖率的价值是一个备受争议的话题,各方观点鲜明并且两极分化,这实在令人惊讶。每次在大的公开场合中提到代码覆盖率,似乎都会引发无休止的争论。这些争论没有帮助我们在这个问题上取得任何富有成效的进展,因为人们会固守在各自的阵营中。本文的目的提供一些思路,引导大家找到共同点,让我们可以向前迈进,切实地用好代码覆盖率能够提供的信息。以下是我们在代码覆盖率方面提出的最佳实践,目标是帮助大家有效地开发出高质量的代码

  • 代码覆盖率为开发人员的工作带来了显著的好处。虽然这不是一个针对测试质量的完美度量指标,但它确实提供了一个合理、客观、具有可操作性数据的行业标准。并且这种度量方式不需要大量的人工干预,普遍适用于所有的软件产品。目前已经有相当多的、支持大多数编程语言的工具可以支持代码覆盖率的度量。但是,我们必须明白,代码覆盖率是一个有损的、间接的指标,它将大量的信息压缩成一个数字(代码覆盖率),所以不应该是唯一的度量指标。相反,我们需要结合其他技术一起使用,对我们的测试工作进行更全面的评估。

  • 单纯用代码覆盖率这个指标是否能指导我们减少缺陷是一个开放的研究课题,但我们的经验表明,在提高代码覆盖率方面的努力往往会带来卓越的工程文化,因此从长远来看,能够减少产品缺陷。例如,优先考虑代码覆盖率的团队倾向于将测试视为头等公民,并倾向于在产品设计中加强可测试性,这样就能以更低的成本实现测试目标。所有这些又会引导团队开发出更高质量的代码(更具模块化,更干净的API契约,更容易管理的代码评审流程,等等)。大家也开始更加关心整体的开发工作是否健康,以及工程和运营的卓越性。

  • 高水平的代码覆盖率并不能保证高质量的测试覆盖率。如果大家痴迷于让代码覆盖率尽可能接近100%,那么会导致错误的安全感。这也是一种浪费:耗费机器资源,并从现在需要维护的低价值的测试中创造出技术债。由于测试不充分导致有缺陷的代码被推送到生产环境中,测试不充分的原因有以下两个:

    (a)测试没有覆盖特定的代码路径,如果是这个原因,我们用代码覆盖率分析很容易识别出来。

    (b)测试没有覆盖代码某个区域的特定边界值,虽然这部分代码的代码覆盖率没有问题。

    分析代码覆盖率来捕捉(b)类问题是比较困难的。代码覆盖率不能保证所覆盖的代码行或分支都已经被测试充分覆盖,它只是保证了测试已经覆盖到这部分代码。要注意的是,不要为了提高代码覆盖率而复制/粘贴测试,或者为了达到某个数字而增加没有实际价值的测试。一个更好的技术是变异测试,它可以评估我们是否对所覆盖的路径进行了充分的测试,并对失败的情况设计了良好的断言

  • 代码覆盖率低肯定说明产品的大部分区域在每次部署前都没有经过充分的自动化测试。这增加了把有缺陷的代码推送到生产环境的风险,所以应该关注代码覆盖率指标。事实上,代码覆盖率的价值不是用来展示哪些代码被覆盖到了,而是帮助我们发现哪些代码还没有被覆盖到。

  • 没有一个普遍适用于所有产品的 "理想的代码覆盖率数字"。针对一组代码的测试范围应该综合考虑以下因素:

    (a)代码的业务影响/重要性;

    (b)代码变更的频率和能够运行到的频率;

    (c)代码的生命周期、复杂性和所服务的领域。

我们不能规定每个团队都要达到百分之多少的代码覆盖率,这是一个业务决策,最好由具有特定领域知识的产品所有者来定义。任何需要达到一定代码覆盖率指标的任务都应该通过测试基础设施的建设让测试变得更简单。例如将相关工具整合到开发人员的工作流程中。要注意的是,在刚开始的时候,工程师们可能会把这个指标当成一个可选项,他们会小心翼翼地让实际的代码覆盖率比设定的目标低。

  • 一般来说,很多产品的代码覆盖率会低于标准,我们应该致力于大幅度提高代码覆盖率。虽然没有一个 "理想的代码覆盖率"目标值,但在谷歌,我们提供的一般准则是60%为 "可接受",75%为 "值得赞扬",90%为 "模范"。然而,我们不提倡自上而下的命令,而是鼓励每个团队自己定义对业务需求有意义的代码覆盖率指标。

  • 不要纠结于如何将代码覆盖率从90%提高到95%。代码覆盖率带来的收益是对数增长的(译者注:在前期,对数增长在短时间数值呈现爆炸性的增长,但这种红利随着时间增加会慢慢下降。越到后期这种增长效果越弱,甚至最终成为一条接近水平的直线。见图1)。然而,如果代码覆盖率只有30%,就必须采取具体措施提高到70%,并始终确保新的代码保持这一目标。

图1 对数曲线

  • 比代码行覆盖率的百分比更重要的是,对未被覆盖的代码行(和行为)进行分析,判断质量风险是否可以接受。分析没有被覆盖的代码比已经覆盖的代码更有价值。在代码评审过程中对未覆盖的具体代码行,我们需要进行切实的讨论。这比起对于覆盖率指标数字过度依赖更有价值。我们已经发现,将代码覆盖率集成到代码评审中,可以让评审速度更快、评审也会变得更容易。并不是所有的代码都同样重要,例如,测试调试日志的代码往往没有那么重要,因此,让开发人员不仅需要了解自己提交的代码的代码覆盖率,而且在代码评审中需要让他们看到详细的覆盖情况,保证最重要的代码被覆盖到。

  • 针对代码覆盖率低的软件系统,应该采取具体的措施来循序渐进地改善它。继承一个测试不充分和可测试性差的遗留系统是令人生畏的,大家可能觉得无力扭转,甚至不知道从哪里开始。但至少,我们可以采用 "童子军规则"(永远保持离开时的露营地比你发现它时更整洁”)。随着时间的推移就会逐渐达到一个健康的位置。

  • 确保经常变更的代码的代码覆盖率是100%。虽然代码覆盖率指标超过90%很可能是不值得的,但每次提交的代码覆盖率(per-commit)应该达到99%,90%是一个下限。我们需要确保测试质量不会随着时间的推移而变得更糟。

  • 单元测试的代码覆盖率只是拼图的一部分,集成/系统测试的代码覆盖率也很重要。在CI/CD流水线中,所有测试类型(单元和集成)的总覆盖率更重要,因为我们可以全面了解有多少产品代码在整个交付流水线中没有被自动化测试覆盖到。应该注意的一点是,尽管单元测试在执行到的代码和测试到的代码之间表现出很高的相关性,但集成测试和端到端测试的某些覆盖具有偶然性,并非特意为之。把集成测试的代码覆盖率纳入到度量范围可以帮助我们避免:单元测试中没有覆盖到某些代码,但我们错误的以为在集成测试中会覆盖到但实际上并没有,这是一种错误的安全感。

  • 我们应该设置代码门禁,限制那些不符合代码覆盖率标准的代码部署到生产环境中。团队应该讨论并决定哪种门禁机制对他们有意义。但是应该注意,不要把它变成一个需要手工填写的选项,因为它能会适得其反(开发人员有"达到指标 "的压力,不会如实填写)。有很多机制可以利用,包括对所有代码的代码覆盖率设置门禁、只对新代码的代码覆盖率设置门禁、对特定的硬编码的代码覆盖率设置门禁、针对上一版本的代码变更部分设置门禁、对代码的特定部分选择忽略或者重点关注。规则明确了之后,开发团队必须坚决遵守,如果代码没有通过代码门禁,这部分代码就禁止被合入并部署到生产环境中。

(可以看出 Google大部分项目的代码覆盖率超过70%)

参考链接:

猜你喜欢

转载自blog.csdn.net/KerryZhu/article/details/125097761