单元测试时“单位”应该是什么?

时间:2009-06-30 23:17:52

标签: unit-testing tdd

今天在Proggit上我正在阅读题为“Why Unit Testing Is A Waste of Time”的提交的评论主题。

我并没有真正关心这篇文章的前提,就像我对comment所做的一样:

  

问题的根源在于商业软件中代码的大多数“单位”   项目很简单。

     

更改单位的大小直到它   不再是微不足道的?谁是地狱   将代码单元定义为单个   功能或方法无论如何!?

  

好吧,我和我一起工作的一些人   想要将单位定义为单一   功能。这完全是愚蠢的。   我最喜欢的“单位”定义是:   代码的最小部分   可以进行有用的测试。

我们是否花费了太多时间来模拟一些对象并测试一些简单的代码而不是真正添加任何有价值的东西?

单位测试时“单位”应该是什么?功能级别测试是否过于细化?

10 个答案:

答案 0 :(得分:14)

引用Wikipedia可能看起来微不足道,但我认为在这种情况下它非常简洁和准确:

  

单位是应用程序中最小的可测试部分。

这似乎与您的问题中的评论一致,即单元是“可以有效测试的代码中最小的部分”。换句话说,让单位尽量小到,这样它对开发人员/测试人员来说仍然有意义

通常,您需要单独测试项目的某些部分,然后测试它们如何相互作用。拥有各种级别(级别)的单元测试通常是明智之举,因为它有助于确保您的代码在各个级别上工作,从单个功能到完整的自包含任务。我个人并不认为测试个别功能是错误的,甚至是无益的,只要他们自己做一些有用的事情,这往往就是这种情况。

说实话,“单元测试”中没有明确或严格的“单位”定义,这正是使用模糊术语“单位”的原因!学习需要测试的内容以及在什么级别上是经验问题,而且通常只是试验和错误。这可能听起来有点令人不满意,但我相信这是一个合理的规则。

答案 1 :(得分:4)

我总是在功能级别进行测试,而且工作得很好。对我来说最重要的是单元测试测试两段代码之间的契约。单元测试只是作为调用者,并确保被测试的代码(无论多大 - 单个函数或需要30分钟测试的巨大嵌套库)以可预测的方式返回结果。

单元的全部要点测试它以确保兼容性(通过不破坏相互作用)并确保可预测的结果。在任何地方进行测试都可以帮助您稳定应用程序。

更新:每当客户或用户报告破坏我的应用程序中的交互的边缘情况时,我也总是添加单元测试。修复它对我来说是不够的 - 添加一个单元测试以确保修复保持可以防止回归,并有助于保持稳定下线。

答案 2 :(得分:4)

“单位”应为您定义的单个原子单位 。也就是说,确切地说,单位测试的“单位”是相当主观的;它可以相当强烈地依赖于您的架构是什么,以及您的应用程序如何选择分解功能单元。我所说的是除了你定义的内容之外,没有明确定义的“单位”。 “单位”可以是具有单一副作用的单一方法,也可以是一组相关的方法,它们共同定义单一,连贯的功能集。

理性在这里非常重要;完全有可能为每个班级的每个访问者编写单元测试;然而,这显然是矫枉过正的。同样,将整个应用程序定义为一个单元是可能的,但是很愚蠢,并期望有一个测试来测试它。

通常,您需要一个“单元”进行测试,以描述一个明确定义的,明显不同的功能块。在查看应用程序的每个级别,您应该能够看到明确的“原子”功能(如果您的设计是好的);对于低级视图,这些可以像“从数据库中检索记录”一样简单,在高级视图中也可以像“创建,编辑和删除用户”那样复杂。他们也不是互相排斥的;你可以轻松地将它们作为单元测试。

这里要点是你要测试的单位是有意义的单位。您希望单元测试验证和验证功能;所以单元测试测试的是你定义为功能的东西。什么是功能单元?这取决于您的个人情况。

答案 3 :(得分:3)

我认为单位是最小的有意义的工作部分,可以与伪代码中的其他步骤分开。

例如,如果您尝试执行一系列步骤来处理某些数据,例如

  1. 扫描数据集中的最小值,最大值,中位数,平均值
  2. 生成直方图
  3. 生成重新映射功能
  4. 重新映射数据
  5. 输出数据
  6. 这些步骤中的每一步都是“单位”,整个系列本身也是一个“单位”(以测试每个步骤之间的凝聚力是否正常)。这些步骤中的任何一个都可以是四个函数(对于第一步,如果程序员运行四个循环),或者一个函数,或者其他任何一个,但最后,已知输入应该给出已知输出。

答案 4 :(得分:3)

如果考虑到墨菲定律,没有什么是微不足道的。

开玩笑并假设一个OO环境,我接近单元测试以一个类为单位,因为通常各种方法修改内部状态,我想确保各种方法之间的状态是一致的。

不幸的是,通常检查一致性的唯一方法是调用类的各种方法以查看它们是否失败。

答案 5 :(得分:1)

通常情况下,单位越小,单位测试就越有用和有效。单元测试的重点是能够将任何新引入的bug本地化到代码的一小部分。

答案 6 :(得分:1)

对我来说,一个“单位”是一个类的重要行为,在未来8-12个月,我不会记得。

通过精心编写的单元测试(想想BDD),我不必这样做,因为我的测试会向我描述并用简单的英语验证代码。

答案 7 :(得分:1)

我怀疑“单元测试”是一个误用的术语。如今,该术语不仅用于指代测试一小段代码,而且还用于任何自动化的测试。

我倾向于在编写代码之前编写我的测试,所以当我第一次编写它时,我不能告诉你,如果它会导致创建一些新行,一个新方法或一个新类。

所以,总之:mu

答案 8 :(得分:0)

  

更改单位的大小直到它   不再是微不足道的?谁是地狱   将代码单元定义为单个   功能或方法无论如何!?

如果测试定义为方法的“单位”太困难,那么该方法可能太大或太复杂,无法创建单元测试。

我遵循 rwmnau 建议的类似方法,并在方法级别进行测试。除了为每个方法创建一个测试之外,我还为每个方法中的不同代码路径创建了附加测试。有时,强调所有代码路径会变得复杂。我的挑战是尽量避免编写方法类型,除非在性能和代码复杂性方面没有更好的解决方案。

我也使用模拟测试组件之间的契约。

答案 9 :(得分:0)

这个问题是古老的,没有确切的答案,但是我认为“任何有意义的东西”或“可以被有效测试的最小零件”都可以加以完善。

有一篇出色的文章被公然命名为“ Unit tests aren't tests”。标题是一个诱饵,它本身就是一本好书,但在这里我只重点介绍相关要点。

  

物理学中有一个叫做“ 新兴”的想法,   与简单规则交互的系统会产生复杂的系统   根据不同的规则行事。例如,原子是相对容易理解的自包含模型。将它们足够多地装在一个盒子里,突然间,您便拥有了整个固态物理学领域。 ...代码出现   太。足够多的交互单元,您的程序要复杂得多   比其各部分的总和。即使每个单元的行为正常且有效   根据其单元测试,大部分复杂性在于   整合。

基本上尝试围绕“可组合单元”组织单元测试,即在组合在一起时不太容易受到出现的影响-但测试仍应足够简单和快速,以被称为“单元测试”。出现的影响无法完全消除,无论如何,单元之间都会隐藏一些复杂性-但是,集成/系统测试可以处理的复杂性相对较小(这反映在“测试金字塔”结构中)。

不幸的是,高组合性和出现的效果无法用工具来衡量,我只能从脑海中浮现出一些想法:

    大量使用模拟和存根是一种气味。无需编写任何有用的测试,即可轻松使用模拟并报告近100%的覆盖率。 纯的不可变单位更容易组合。在纯函数式编程中,通常非常高级别地进行“单元测试”。
  • 对于设计不良的系统,没有“正确”的单元测试级别。无论您尝试测试什么单位,它都会显示出出现状态。这就是为什么在重构一些由意大利面条编码的旧系统时,投资于集成测试的常见建议。