单元测试 vs. 验收测试

75

你是支持单元测试还是验收测试?或者两种都支持?

我的理解是:

  • 单元测试:从开发人员的角度验证系统
  • 帮助开发人员实践TDD
  • 保持代码模块化
  • 有助于在较低粒度上检测错误

验收测试:

  • 从业务和QC/QA的角度验证系统
  • 通常由不熟悉代码内部工作原理的人编写,因此更高层次

我认为两者都是必要的。但是,为了减少重复工作,将单元测试纳入验收测试中是否明智?换句话说,让后者调用前者。反过来做有没有意义呢?

你对单元测试和验收测试有何想法?如何管理它们之间的关系?

5个回答

102

验收和集成测试可以告诉您代码是否正常工作并且完整; 单元测试可以告诉您它在哪里出了问题。

如果您已经对验收和集成测试做得很好,并且它们通过了,那么您的代码将实现所有应该实现的功能,并且它是可用的。这很不错(也很好知道它不行)。 但是,如果不起作用,则验收测试不会让您了解发生了什么错误;因为它测试了许多功能单元,所以它可能是一种鸟瞰失败的视图。这就是单元测试脱颖而出的地方。良好的单元测试可以确切地告诉您出了什么问题,以及哪个部分的代码有问题。比起验收测试,确定是否编写了足够的单元测试更加困难,但当您遇到验收测试失败却没有相应的单元测试失败时,就需要编写单元测试了。

这只是从测试角度来看。当然,TDD(测试驱动开发)并不是关于测试。就设计驱动而言,验收测试为您提供了一个广泛的路线图(“这是您想要去的地方”),而单元测试则带您走向下一个交叉口(“向左转”)。在这方面,它们都很有价值,而且它们的价值互补。

不要混淆它们;不要混合使用它们。特别是单元测试不应该依赖于其他任何内容,通过让验收测试依赖于它们来限制您的单元测试将是一个错误。当然,它们可以共享一些框架代码,但它们应该是独立的。


谢谢,卡尔。您能否再详细解释一下为什么我们不应该通过将验收测试与单元测试捆绑在一起来限制单元测试呢? - Calvin
6
如果一个自动化测试使用了单元测试,那么当我们发现更好的设计适用时,我们就不太能自由地更改这个单元测试。每次使用代码都会限制它,而过于受限的代码(甚至是测试)会变得脆弱。单元测试应该非常可塑,这样我们才能重构它们以适应新的需求和想法。 - Carl Manaster
您将验收测试描述为运行并提供结果的软件部分,但这与我对该术语的理解完全不同。 - reinierpost
4
混种?所以,不要在单元测试和验收测试中“种族混合”……我不得不查了一下 :-) - Rubin Simons

22

总结以上内容:

  • 验收测试确保你正在构建正确的事物
  • 单元测试确保你正在以正确的方式构建事物

15
然而,为了最小化冗余工作,将单元测试纳入验收测试中是一个好主意吗?
不。
换句话说,让后者(验收测试)调用前者(单元测试)。反过来行不通。
验收测试通常是政治性的。你向那些根据直觉决定接受或拒绝的人展示它们,然后你就会争论验收测试的有效性。
然后你会争论工作范围和下一个发布版本。
验收测试通常不是技术性的。如果是,那么你就需要正式的单元测试。
不要试图调整政治气氛。接受它,让它发生。
您可以希望验收测试驱动开发(ATDD)能够实现“所有团队成员在开发之前都同意编写验收测试”。但是你必须反映这样的现实:预先编写的任何内容都是虚假的,最好只是有商量余地的。
所有敏捷方法的前提是你只能同意达到可发布的东西。之后的一切都是可以协商的。
所有测试驱动(TDD,ATDD或其他)背后的前提是测试是铁杆协议。但事实并非如此。使用任何TDD(或ATDD)方法,你可以原则上同意测试结果,但你实际上并没有同意测试本身。
可能会出现无法轻松编写测试的情况。或者更糟糕的是,根本无法编写测试。你可以同意看起来可以测试的结果,但结果可能会定义不清。现在怎么办?这些是直到开始开发并进入细节才能知道的事情。

所有的测试都很重要。没有任何一种特定类型的测试可以作为其他任何一种测试的超集或子集。它们总是部分重叠的集合。试图将它们组合起来以某种方式节省一些工作可能会被证明是浪费时间。

更多的测试比任何其他东西都更好。所有测试的联合比试图强制在测试之间建立子集-超集关系更有价值。


感谢您的回复。在ATDD中,验收测试是早期编写的,明确和具体的,对吧?也就是说,它们不用于接受或拒绝任何已交付的功能,而是用于指定应该交付哪些功能。开发人员知道他们的代码必须通过验收测试才能认为它完成了。 - Calvin
@Calvin:在“验收”测试和其他任何测试之间存在固有的歧义。所有测试都接受或拒绝功能。所有测试。如果测试失败,则拒绝功能。如果测试通过,则接受功能。 - S.Lott
我应该澄清一下。我的意思是从验收测试驱动开发(ATDD)的角度来看验收测试。其信条是在开发之前,整个团队都要编写并达成一致的验收测试。然后开发人员会有意识地编码,以达到使所有验收测试通过的最终目标(即满足先前定义的所有要求)。 - Calvin
@Calvin:“ATDD”与TDD没有实际区别,也没有与实践中的单元测试不同。唯一的小差别是“验收”测试对用户更加可见。但是它们之间没有“包容性”。它们只是更多的测试。测试就是测试。由于可见性是唯一的区别,不要过度思考。 - S.Lott
感谢您昨天添加的额外想法,S。 - Calvin
@S.Lott 很多时候,随着开发人员的进步,测试总是成为一个问题。当开发人员在已经习惯了他们的工作流程之后被介绍到测试时,他们很难跨越这个障碍。我认为这部分原因是由于不同名称、同义词的混淆以及缺乏任何人给出简单、短小、平凡的英语解释... 直到现在!您好先生已经掌握了比许多人更高级别的英语语言,并且已经非常优雅地使用它。因此,您拥有我的最深敬意。 - Kirill Fuchs

14

单元测试 - 确认我的特定函数只做它应该做的事,没有多余或少于的内容。

验收测试 - 确认我的应用程序能够正常工作。

例如:一个计算二次函数根的应用程序。它接受a、b和c三个参数,返回x1和x2两个答案。该应用程序是由我编写的函数构建的,这些函数包括加法、减法、乘法、除法和平方根等基本运算。

单元测试 - 检查我的除法和乘法函数是否正确工作,以及我的平方根、加法和减法函数是否正确。

验收测试 - 确认我的应用程序能够计算二次函数的根。

由于我的整个应用程序的目的就是计算根,所以不应该对计算根进行单元测试,因为没有单独执行该功能的函数。


2
以下是我对一些测试问题的个人看法:
然而,为了减少冗余工作,将单元测试纳入验收测试中是否明智?我同意S. Lott的观点,并补充说这里存在一定的风险,即单元测试可能被操纵以通过某些错误。例如,在下拉菜单上,有人可能会测试几种状态,但可能不会测试所有状态,而测试人员则可能使用不同的数据来发现潜在的错误。
换句话说,后者调用前者。反向进行是否有意义?我会小心地将它们耦合在一起。单元测试代表了对最小功能单元的测试,通常是如此之小,以至于最终用户可能无法理解需要进行数百次测试才能得到一个可用于输入数据的网络表单。验收测试更多地关注应用程序用户所需的内容,这可以更加主观,例如“这看起来漂亮吗?”与“这看起来正确吗?”验收测试中可能存在“足够好”的标志,我不确定这种标志是否适用于单元测试。一般来说,如果单元测试失败,则必须决定修复代码还是删除测试,具体取决于情况。
总的来说,单元测试是验证最简单代码片段的过程。还有集成测试,但这是更高级别的测试,一旦检查了所有小部件,这些部件的组合是否能够协同工作,例如我小时候看过的周六早晨动画片中有一些玩具可以组装,如“Voltron”或各种变形金刚,如构建者,他们组成了毁灭者。验收测试通常是从最终用户的角度来看待的,“现在我可以用应用程序做X吗?”在某些情况下,可能会检查一些错误情况,但通常不会对应用程序中可能输入的每种组合进行全面测试。但是,单元测试可能涵盖边界条件和其他几个类似随机的情况。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接