在代码审查期间编写测试是否有益?


24

我的一个同事提出了一个我发现很有趣的想法。

假设我们不做TDD,那么由进行审核的人员在代码审阅期间编写测试是否有益?

对于这个问题,假定这是一个纯粹的学术项目,因此没有生命危险。而且该团队是4个人。每个人都知道该语言,并且熟悉所使用的所有工具/库/框架,并且可以编写测试。因此,基本上不是高级全职首席忍者工程师,而是体面的编码人员的人。

我发现的优点:

  1. 鼓励在审阅期间对代码有更深入的了解,以编写有意义的测试。
  2. 然后,您可以添加由正在测试的代码的作者进行的那些测试的代码审查。

我发现的缺点:

  1. 代码编写和测试之间的反馈循环不断增长。

编辑:我知道它不能在“正常”的Web应用程序上正常工作。我想到的是一个极端的案例,在该案例中,您需要实施复杂,科学的算法,这些算法都需要注意细节。让我们假设实现自己的图形库,NLP等。我想知道我们正在编写的代码是否与数据库隔离,并且这样很难理解却不会增加控制级别,而另一个需要了解源代码的人代码并进行有意义的测试,从而使整个过程不太容易受到那些不太明显的bug的影响,这些bug不会使应用程序崩溃,但最终会使您的结果混乱?


3
您没有提到这一系列测试是否超出了开发过程中应该进行的测试或替代了它。
罗比·迪

3
如果“我们不做TDD”,则写单元测试(等距测试)将是有益的,但相当困难,因为非tdd代码通常很难隔离。如果您没有允许您定义可再现的,非脆弱的前提条件的数据库抽象层(存储库api),那么编写验收测试和/或集成测试也将很困难和/或脆弱。
k3b

4
@JoulinRouge:TDD对此有所帮助。由于没有代码,因此无法根据代码定制测试。
约尔格W¯¯米塔格

6
听起来这将是一段很长的代码审查。
大卫说莫妮卡(Reonica)

2
我曾在一个同行评审的地方工作,该同行评审让一位资深程序员检查您所写的每一行,并根据样式准则和最佳实践对其进行检查,并编写您不希望编写的单元测试。
candied_orange

Answers:


7

由代码审查人员在代码审查期间编写测试是否有益?

我发现编写测试的好时机是当您意识到需要针对某种情况进行测试时。

计算机的任务切换非常昂贵,对人类而言更是如此。

此时,您通常对测试的要求和依赖项有了很好的了解。因此,请充分利用您的团队对问题的关注。如果您将来需要完善新的测试,那很好,您已经有测试框架/固定装置,您要做的就是更改需要改进的部分。

如果在代码审查期间发生这种情况,为什么不继续这样做呢?我以前做过。我发现它总比没有好,特别是如果您可以快速完成它,甚至如果不这样做则更好。

假设我们不做TDD?

即使您练习了TDD,如果您意识到在进行代码审查时也需要测试,而您没有,那为什么不在那里写测试呢?

优点

  • 您可以将精力集中在正在检查的代码上。
  • 有时,当人们不参与代码审查时,他们就会成为视频群聊和聊天的时间。编写测试鼓励每个人更加积极地考虑正在审查的代码。
  • 团队中的其他初级成员将有机会从测试写作经验中学习。
  • 您可能会在团队中找到自己不知道的人才。

更多测试可能导致更多代码真的是一个弊端吗?如果需要测试,并且测试需要代码,而现在您已经拥有了,那就太好了

注意事项

也许某些团队需要专注于其他事情。如果它导致优先级分散,或者您的代码检查超出了计划,那么您就需要限制或减少测试的实际编写。但是,代码审查当然可以确定需要编写的测试,并且也许至少可以将它们存根以供编写者稍后完成。


22

请注意,这是一个很棒的主意。不要将开发人员的书面测试替换为审阅者的书面测试。让您的审稿人查找可能破坏代码的特殊情况和输入。换句话说,让他们尝试编写原始开发人员不希望编写的新测试

编写特性测试是绝对了解您未编写的代码的绝妙方法。让您的审阅者对代码进行其他测试可以使他们更好地了解代码的工作方式,如何破坏代码以及如何对其进行改进。一直以来,都增加了代码覆盖率。

这些都是我书中的胜利。


5
几乎就像您有审查代码的经验一样……
syb0rg '16

不知道您在说什么@ syb0rg ...您无法证明这一点。=;)-–
RubberDuck


2
此外,测试用例几乎是描述在审查中发现的缺陷的最不明确的方法:-)
史蒂夫·杰索普

1
@ syb0rg Rubber Duck已帮助成千上万的程序员修复了他们的代码。谁比看得那么多的代码更有资格审查代码?
jpmc26

18

我认为这个想法并非完全没有道理-但是,TDD等人的主要好处是可以及早发现问题。开发人员也最适合发现哪些角落情况可能需要特别注意。如果在代码审查之前将其保留,则可能会丢失此知识。

在代码审查期间编写测试会遇到与传统手动测试相同的问题-对业务规则的理解可能会因开发人员的不同而有所不同。

关于开发人员是否知道如果在上游有测试功能可以捕获更严重的错误,是否会很好地测试他们的代码,也将进行古老的讨论。


好答案。但是,如果我们因为人们不愿意而我又没有对他们的影响力而不会做TDD,但是我们需要确保我们得到的结果不是误报,那是由于错误使我们的结果歪曲了怎么办?主要的风险是人们可能会在没有适当理解的情况下急于实现某些东西,在编写测试时就带着不正确的理解,使测试通过但最终产生错误的代码。也许结对编程可以解决问题?但是再一次,很容易迫使人们理解某人的某些东西。
Sok Pomaranczowy,

我认为也许和编写测试的其他人一样,可以在开发进行中针对开发代码运行这些测试。有问题的开发人员必须与代码所在位置位于同一页面上,否则编写代码的开发人员可能会不断地对失败的测试进行防火处理,而不是使事情真正生效。
罗比·迪

该问题称为“构想偏差”。
ArT

实际上,我会这么说,这会分散代码审查过程的注意力,并且代码会影响测试过程,而这并不是您想要的,这消除了使用单独的测试人员和编码人员的主要优势。
ArT

1
@RobbieDee如果责怪的接收者实际上很重要,则说明您的开发环境不健康。这比错过一些有用的测试要糟糕得多。
jpmc26 2013年

5

我同意@RobbieDee的回答,但还有一点要补充。

如果您真的喜欢这个想法,为什么不让相同的人在代码之前编写测试作为用户故事的可执行接受标准?

那会做同样的事情,仍然保持简短的反馈,并让每个人都围绕这个故事进行讨论,我认为这将具有更大的价值。

不利的一面是可能会出现无休止的验收标准:-(我想您正在尝试让代码审查人员来了解实现代码,但我建议使用结对编程和循环对作为更好的解决方案这个问题。

OP添加了一个编辑,在那里他们布置了更多的细节,这是一个困难的或算法繁重的功能。

对此,我要补充一点,您有更多的机会关注问题和解决方案的本能是好的。也许一对多地一对一地配对,直到每个人都看到了实施代码和测试的真正困难。每个人都抛出新想法并增加更多价值。

有时有一个想法叫暴民编程,就像配对但与更多人在一起。这几乎是您在谈论的内容,但是它们在撰写本文时会有所帮助,而不是在随后的正式复审中提供帮助。这并不适合每个人,并且可能需要强大的驱动程序(领导者)才能使其正常运行,或者需要彼此和流程非常融洽的团队。

在进行mob编程之后,我想这样做会产生与许多人相同的优点,很多人看到问题并提出改进建议,如果这是您的团队满意的操作方式,那么那会有所帮助,但我会尽力保持必要的这种情况的发生率降到了最低,因为我认为这可能会降低团队的速度。


也许开发人员应该按照自己的意愿编写测试,然后将其上传到存储库中,但是进行审核的人员应该编写自己的测试,而永远不要看开发人员编写的测试。如果两个测试套件都通过了所有测试,但如果审阅者测试失败,那么可能有问题吗?
Sok Pomaranczowy

1
@SokPomaranczowy过去尝试过在从不同的人编写测试中添加冗余。我认为,如果您不是在使用至关重要的软件,那将是浪费时间,而应该将精力集中在最好的时间上(您永远不会编写所有测试),并与团队保持良好的沟通,我认为是一种更好的方法。
Encaitar '16

@Encaitar我同意,这听起来像是一个巨大的时间消耗,可能无法使事情变得更好。投资回报率和所有这些…
萨拉

3

就像您说的那样,如果您正在运行TDD团队,那么这很无聊,因为代码应该已经过测试。

总的来说,我认为这并不是一个好主意,但这取决于您当前的方法以及对您有用的方法。基本上,我看到的问题是您失去了测试的“短反馈循环”优势。即使您正在编写新代码,也可能在中断某件事时立即获得通知,这才是测试真正发挥作用的地方。如果您将测试推迟到代码审查之前,您基本上是在说:“好吧,我们可以在更短的时间内,更少的人员参与下解决此问题,但是至少我们都学到了(也许)”。我更愿意只是确保人们将经过测试的代码提交进行审查,然后再判断测试的正确性和可维护性。毕竟,代码审查仅用于审查,而不是用于编写代码。

另一方面,我确实建议您在复习期间使用测试/代码。尝试破坏一些东西。注释掉一个if条件。用字面值true / false替换布尔值。查看测试是否失败。

但是,总的来说,我建议您将测试与代码一起编写,然后立即进行全部检查。


2

这取决于您在代码审查中的工作。我认为在该阶段编写测试的主要原因有两个:

  • 首先,如果您在代码检查期间也进行了重构,并且注意到没有足够的单元测试来涵盖您要应用的重构类型,请添加此类测试

  • 其次,如果代码看起来像您可能有错误,并且您希望它证明(或拒绝)此错误,则为其编写测试

两种情况都表示需要进行当前尚不存在但应该存在的测试。当然,是否应该由审阅者或原始作者来编写这类测试,但这取决于您的团队文化,但是应该由他人来编写测试。

实际上,我认为这不适合仅适用于“复杂,科学的算法”的“极端情况”,相反,它适用于您希望从中获得一定质量的任何一种软件。


2

不,不要这样做。您会让他们认为TDD令人恐惧。

我认为@ k3b在有关该问题的评论中是正确的。通过TDD风格的过程编写的代码在外观和交互方面与未进行测试的代码非常不同。在未经测试的代码中添加(良好)测试通常需要大量重构代码,以阐明其意图和活动部分。

通过在编写代码后添加测试,您会错过TDD的体系结构方面的好处(在我看来,这是主要的好处之一)。不仅如此,您还要求其他人(对代码不太熟悉的人)选择添加已经很难添加的测试。

添加测试的人员将不得不大幅重构代码,或者他们将不得不非常努力地测试无法测试的代码。无论哪种方式,他们都不会享受这种体验。即使这可能不是经典的TDD,他们也不会那样看,您可以一劳永逸地将它们从TDD中删除。

(如果您已经在遵循TDD流程,那么在代码审查期间编写其他测试的危害就较小,尽管以我的经验来看,如果这些测试已经编写良好,那么向提交该文档的人解释额外的测试就很容易了。代码进行审核,并让他们编写代码。)


1

代码审查期间的单元测试不能替代开发期间的单元测试。

从直觉上来说,您的建议很有意义。该评论有什么用?检查代码是否正确。测试是为了什么?检查代码是否正确。那么为什么不将两者结合起来呢?

这就是为什么。

对代码进行测试是艰巨的工作。编写对一件事有意义的代码是一回事。编写可以进行有效测试的代码是另一回事。现在代码可以在“实际工作”和“测试”两种情况下运行的事实要求更大的灵活性,要求该代码能够以有意义的方式独立存在。

编写代码以使其可测试是额外的工作和技巧。重构别人代码以实现可测试性(如果一开始就没有考虑到可测试性的话)可能是一项主要任务。

您正在开发人员和审阅者之间重复工作。大概,您的开发人员不会在没有至少一定程度的信心的情况下将其代码提交审查。他已经需要测试代码。现在,存在不同的测试级别和范围。质量检查人员在开发人员审核人员之后对代码进行测试。但是,无论范围,你认为是适当的开发和评审,这是没有意义的开发商要弄清楚如何测试代码,这个水平一次,但让他测试一次性和难以复制,然后将在审稿再次进行测试,这一次是自动化且可重复的。你只是有两个在编写相同的测试,他们的投资时间-一旦不佳,一次良好。

您正在将审查变成更长,更费力的步骤。如果测试是审查过程的主要部分,那么当某些测试失败时会发生什么?审稿人负责使测试全部运行,因此她还需要调试代码吗?还是要来回敲击,一项写作测试,另一项使它们通过?

有时,您可以编写一大堆相互正交的测试,因此您不需要乒乓球。审阅者编写了十二个测试,其中一半失败,开发人员修复了错误,所有测试仍然有效,并且现在通过。但是...很多时候,您遇到了阻止程序错误,或者需要重新设计和更改API的错误,或者没有。如果您要承担在审阅者和开发人员之间来回传递测试的责任,那么您实际上不在审阅阶段。你还在发展。

需要编写测试并不能激发更全面的审查。从根本上讲,这意味着您越深入,必须编写的测试就越多,并且可能它们将是需要深入系统的测试。

与编写测试的开发人员相比,他的动机是:如果我不编写重要的测试,审阅者将在审阅中指出。

如果审阅者需要检查代码的全面测试,甚至是审阅者,那么如果她需要自己决定何时可以停止编写深度挖掘测试并只需执行代码审阅,就可以对系统有更好的了解。

如果开发人员未编写单元测试,则审阅者也不会。采用测试作为普遍做法存在许多障碍。也许您承受的压力太大,并且很难测试您的代码库。也许您没有那么丰富的测试经验,并且觉得您负担不起学习曲线。也许您有个斧头杀人犯,向编写测试的人发送了威胁性笔记。我不知道!

但是,无论原因是什么,可以肯定地认为,它同样适用于审阅者和开发人员。如果团队感到压力很大,那么审阅者没有比开发者更多的时间(如果她愿意,则可以重新分配工作,这样人们就不会那么紧张)。如果没有人知道如何很好地编写单元测试,那么审阅者可能也不会这样做(如果她这样做,则应该坐下来教队友)。

这个建议听起来像是试图将钱从一个同事转移到另一个同事。而我只是没有看到任何方式,为工作顺利,首先是因为它真的很难(不健康),以产生一种情形,一个人是唯一一个谁可以做测试,和其他人不能做完全没有任何测试。


什么的工作是具有审查盖测试以及。如果开发人员已经编写了十个测试,那么与开发人员没有编写任何测试相比,审阅者更有可能建议另外十个测试。

而且,如果测试极端情况是一项主要任务,那么在整个团队中更广泛地分发它可能是有意义的。**一旦代码可以首先进行测试,编写更多测试就变得容易得多。**

回顾是发现关键案例的好时机。而且,如果审阅者可以加入并为她发现的极端情况编写测试,那么嘿-更好!但总的来说,假设审阅者可以在开发人员听起来不是一个很糟糕的主意的地方编写测试。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.