代码审查“查”什么(2):测试

在上一篇我们谈了很多可以在代码审查时留意的事情。现在我们会聚焦这个关注点:在测试代码中找什么。

本文假定:

  • 你的团队已经为代码写过自动化测试。
  • 测试在持续集成(CI)环境下定期运行。
  • 审查的代码已经经过自动编译和测试流程,结果也通过了。

这篇中我们会将介绍审查者在查看测试时需要考虑的事情。

新的或修改的代码有测试吗?

无论是修改 bug 还是新功能开发,几乎没有新代码不需要一个新的或更新过的测试去覆盖它。甚至类似性能这样的非功能性修改,也被证明往往需要经过测试验证。如果在代码审查中没有测试,作为审查者你应该问的第一个问题是“为什么没有测试?”。

测试有覆盖到代码中令人困惑或者复杂的部分吗?

比提出“有测试吗?”这个问题更进一步是要回答这个问题,“重要的代码是否被至少一个测试覆盖?”。

检查测试覆盖率无疑是应该自动化的。但我们不仅仅可以检查覆盖率的明确百分比,还可以使用覆盖率检测工具来确保被覆盖到的代码位于正确的位置。

考虑下面这个例子:

你可以检查新代码(应该容易识别,特别是当你使用类似 Upsource工具)的测试覆盖率报告以确保充分覆盖。

上面这个例子,审查者可以让作者增加一个测试去覆盖 303 行 if 判断为真的情况,因为测试工具标记304-306 行为红色,说明他们没有被测试到。

对于任何团队而言,100 % 的测试覆盖都是不现实的目标,深入了解哪些代码需要被覆盖到,比工具得出的数字更有用。

你特别想检查所有的逻辑分支和复杂的代码都有被覆盖到。

我能理解这些测试么?

进行测试,提供满意的测试覆盖率是一件事,但如果我这个人无法理解这些测试,那它们的使用就被限制了。当它们出了问题该怎么办?很难知道要如何修复它们。

考虑下面这个测试:

这是一个很简单的测试,但是我并不完全确定它测试什么。它是测试 save 方法?还是 getMyLongID ?而且为什么同样的事需要做两遍?

下面测试的意图可能更清楚:

阐述测试目的所采取的特定步骤,取决于你使用的语言、库、所在团队和个人喜好。这个例子证明通过选择清楚的名字、内联常量和增加注释,作者可以让一个测试对于开发者而言更容易阅读,而不仅是他(她)自己。

这些测试需要满足什么要求?

这是一个需要专门知识的领域。无论这些审核的代码需要满足的需求是在正式文档里,或许在一张用户故事卡中,还是在用户提交的 bug里,被审查的代码都需要满足一些基本要求。(译者注:在scrum开发流程中,用户故事 User-Story 是从用户的角度来描述用户渴望得到的功能,通常写在一张卡片上)

审查者应该找到最初的需求来确认:

  1. 无论是单元测试、端对端测试、还是其它的测试,这些测试是否满足这些要求。比如,如果要求是“允许特殊字符‘#’,‘!’ 和 ‘&’ 出现在密码字段”,就应该有一个在密码字段使用这些值的测试。如果测试使用其它的特殊字符,则不能证明代码符合要求。
  2. 测试需要覆盖所有的要求。在我们特殊字符的例子中,要求可能继续“……如果输入了其它特殊字符,给用户提示一个错误信息”。审查者在这里应该检查是否有一个测试来确认当使用一个错误字符会发生什么。

我可以考虑没有被现有测试覆盖到的用例吗?

通常我们的要求不是清晰明确。在这种情形下,审查者应该考虑最初的 bug、问题、用例中没有考虑到的边界条件。

例如,我们有一个新功能,即“让用户可以登录系统”,审查者应该想:“如果用户输入的用户名为空会发生什么?”。或者“如果系统中不存在该用户,会发生什么错误?”。如果被审查代码有这些测试,审查者就比较有信心代码本身会处理这种情况。反之,如果这些异常用例不存在,审查者就不得不仔细检查代码,看它们是否有正确处理。

如果代码里有但没有相应的测试,要由团队决定你们的策略 —— 是否需要让作者加上这些测试?或者你觉得通过代码审查保证边界条件被覆盖到就好了?

这些测试是否有说明代码的限制条件?

审查者经常会看到审查代码中的限制条件。这些限制条件有时是故意设计的 —— 例如,一个批处理最多只能处理 1000 个条目。

一种说明这些刻意限制条件的方法就是明确地测试他们。在上个例子,我们可以用一个测试来证明当批处理大小超过 1000,会有某种异常发生。

自动化测试中,不必表明这些限制条件,但如果作者写了一个测试表明他们实现中的这个限制,这就意味着这些限制是有意的(有文档说明的)而不是疏忽造成的。

审查代码中的测试类型、测试级别正确吗?

例如,如果单元测试就足够了,作者还需要做昂贵的集成测试么?他们写的性能微基准能不能在 CI 环境下以一致方式有效地运行呢?

理想情况下自动化测试会尽可能快地运行,这样就不需要用昂贵的端对端测试去检查所有类型的功能。用一个数学运算或者布尔逻辑检查的函数,可以很好地替代方法级单元测试。

有没有针对安全性的测试?

代码安全性可以从代码审查中受益。我们后续将有一篇安全方面的文章,但就测试而言,我们可以编写测试覆盖一些常见问题。例如,我们上面提到的登录代码,我们可以写一个测试,看如果没有授权我们是否无法进入网站中被保护的区域(或称为保护 API 方法)。

性能测试

在上篇中我谈到性能是审查者需要检查的部分。自动化性能测试是另外一类测试,我本可以在本篇探讨,但后面会写一篇在代码审查中具体看性能方面的文章,我们在那里再讨论这种类型的测试。

审查者也可以写测试

不同组织有不同的代码审查方法 —— 有时非常明确地要求作者负责所有的代码改动,有时会和审查者协作由审查者自己提交代码的评审建议。

无论采取哪种方法,作为审查者你会发现,写一些额外的测试去玩一下审查的代码,对于理解代码是很有帮助的。类似地,你也可以启动UI界面尝试一下新功能,同样也是很有意义的。有些方法和工具可以很容易被用来试验代码。从团队的利益出发,在代码审查中要让代码和玩代码变得尽可能容易。

提交额外的测试作为审查的一部分当然很好,但也不是必须的,例如这个实验已经给我这个审查者满意的答案。

总结

无论你在组织中如何执行,做代码审查有很大好处。代码审查可以在代码集成到主线之前,就发现代码中可能出现的问题。这个阶段,开发者还记得来龙去脉,修正问题的成本也不高。

作为一个代码审查者,你应该要检查最初的开发者放在他(她)代码中的想法,哪些情况下会变坏,处理边界条件,用自动化测试“记录”预期的行为(正常条件和异常情况)。

如果审查者查找已有的测试,检查测试的正确性,那么你们团队对代码会很有信心。而且,如果这些测试在 CI 环境下被定期执行,你可以看到这些代码一直可以工作 —— 他们提供了自动化回归检查。如果代码审查者很看重他们审查的代码,要求高质量的测试,那么这个代码审查的价值在审查者按下“接受”按钮后,还会延续下去。

打赏支持我翻译更多好文章,谢谢!

打赏译者

打赏支持我翻译更多好文章,谢谢!

任选一种支付方式

1 2 收藏 评论

关于作者:至秦

Linux,Networking 个人主页 · 我的文章 · 53 ·  

相关文章

可能感兴趣的话题



直接登录
跳到底部
返回顶部