在谈论单元测试时,“ DAMP not DRY”是什么意思?


345

我听说有人说单元测试(例如nUnit,jUnit,xUnit)应该是

潮湿干燥

(例如,单元测试应包含“潮湿的代码”而不是“干燥的代码”)

他们在说什么?


2
保证非DRY代码的单元测试没有什么特别的。编写非DRY测试是懒惰的程序员的借口,试图为自己的懒惰开辟疆域。简而言之,DRYness和可读性是正交的问题。
Acumenus

2
DRYness增加了代码导航距离,从而导致更高的思维负担。这在基于“正常”文本的环境中有效。投影编辑器可以减少代码的正交性,但并非在每种情况下都可以。
彼得

Answers:


594

这是平衡,而不是矛盾

DAMP和DRY并不矛盾,而是它们平衡了代码可维护性的两个不同方面。可维护的代码(易于更改的代码)是这里的最终目标。

DAMP(描述性和有意义的短语)提高了代码的可读性

要维护代码,您首先需要了解代码。要理解它,您必须阅读它。考虑一下您花多少时间阅读代码。好多 DAMP通过减少阅读和理解代码所需的时间来提高可维护性。

DRY(不要重复自己)可提高代码的正交性。

删除重复项可确保系统中的每个概念在代码中都有一个权威的表示。对单个业务概念的更改导致对代码的单个更改。DRY通过将变更(风险)仅隔离到系统中那些必须变更的部分来提高可维护性。

那么,为什么在测试中可以接受重复?

测试通常包含固有的重复,因为它们一次又一次地测试同一件事,仅使用稍微不同的输入值或设置代码进行测试。但是,与生产代码不同,此复制通常仅隔离到单个测试夹具/文件中的方案。因此,重复操作是最少且显而易见的,这意味着与其他类型的重复操作相比,它对项目造成的风险较小。

此外,消除这种重复会降低测试的可读性。以前在每个测试中重复的详细信息现在隐藏在某些新方法或类中。为了获得测试的全貌,您现在必须在精神上将所有这些部分放在一起。

因此,由于测试代码重复通常带来较少的风险,并提高了可读性,因此很容易看到它如何被接受。

原则上,在生产代码中赞成DRY,在测试代码中赞成DAMP。两者同等重要,但只要稍加一点智慧,您就可以平衡自己的利益。


18
这是一个很棒的简洁摘要。我还想指出,面对不断变化的需求,DAMP测试更具弹性,而当其他人被要求重写您的测试以适应新要求时,衡量测试的明显性是一个巨大的好处。Jesper Lundberg在这个问题上也有很好的论述。
杰森

3
@ Jason,Btw是否与“ Jesper Lundberg在此主题上也有不错的论述”有关
Pacerier,2015年

2
@JohnSaunders,您可以使用测试数据构建器模式来避免某些重复:natpryce.com/articles/000714.html
si618 '16

2
通过引入神秘来宾
jayeff

1
我还要补充一点,写得很好的测试本质上是您的应用程序的文档/注释。因此,更具描述性有助于向其他开发人员解释您的意图。正如OP所说,它们是每个测试中的自包含内容,因此对您的应用程序的危害最小。更糟糕的情况是您有冗余的测试或测试设置,并且运行测试套件所花费的时间更长。我宁愿在良好的测试覆盖率方面犯错。
Lee McAlilly

60

DAMP-描述性和有意义的短语。

“ DAMP not DRY”表示重新使用代码后的可读性。测试用例中的DAMP而不是DRY的想法是,测试应该易于理解,即使这意味着测试用例有时具有重复的代码。

另请参见单元测试中重复代码是否更可容忍?对于这种观点的优点进行一些讨论。

它可能是Jay Fields在领域特定语言方面创造的。


1
好的答案,并链接到相关问题。没有完美的DAMP vs DRY选择。我们希望代码尽可能干燥,而在测试中则意味着不那么干燥,以至于测试变得难以理解。当测试失败时,我希望原因显而易见,以便开发人员可以开始修复SUT,这意味着我倾向于测试中的DAMP代码。像大多数编程概念一样,总是有可能走得太远。如果您的单元测试代码过于干燥,以至于需要花费较长的时间来确定测试失败的方式和原因,则可能是“过于干燥”。
杰拉尔德·戴维斯

29

“干燥”是“不要重复自己”

这是一个用来告诉人们编写可重复使用的代码的术语,这样您就不必一次又一次地编写类似的代码。

“ DAMP”是“描述性和有意义的短语”。

该术语旨在告诉您编写可以被看过它的人容易理解的代码。如果遵循此原则,则将具有描述性长的变量和函数名称等。


15
AIUI,DRY不仅仅是通过可重用性来节省时间的问题-它还可以防止不同的代码路径“不同步”。如果您在多个类中复制粘贴相同的逻辑,则在需要更改时,将需要更新该代码的每个实例。(而且不可避免地其中之一不会,并且在运动时会炸毁。)
Andrzej Doyle

20

Damp =“描述性和有意义的短语”-您的单元测试应该可以被“读取”:

可读性比避免冗余代码更为重要。

从文章:

DAMP代表“描述性和有意义的短语”,与DRY相反,并不是说“一切看起来都像垃圾堆,不可能阅读”,因为可读性比避免冗余代码更重要。

这是什么意思,在哪里使用?

DAMP主要在编写测试代码时适用。测试代码应该很容易理解,以至于可以接受一些冗余。



11

这里已经有几个答案,但是我想添加另一个答案,因为我认为他们不一定尽其所能地解释它。

DRY(不要重复自己)的想法是,在您的应用程序代码中,您要避免冗余或保护性代码。如果您的代码需要多次执行,则应该为其提供一个函数或类,而不是在多个位置重复类似的代码。

这是一个众所周知的编程概念。

DAMP(描述性和有意义的短语)适用于您的单元测试。这里的想法是,您的单元测试方法名称应该是长而描述性的-有效地描述您所测试内容的简短句子。

例如: testWhenIAddOneAndOneIShouldGetTwo() { .... }

当您读取这样的DAMP方法名称时,您应该完全了解测试编写者试图达到的目的,甚至不必阅读测试代码(尽管测试代码当然也可以遵循这个概念,但使用冗长的变量名,等等)。

这是可能的,因为单元测试方法具有非常特定的输入和预期的输出,因此DAMP原理对其非常有效。您的主应用程序代码中的方法不太可能具体到足以保证这样的名称,特别是如果您已牢记DRY原理编写了该方法。

DAMP和DRY并不矛盾-它们涵盖了代码编写的不同方面-但尽管如此,它们通常不一起使用,因为考虑到DRY原理编写的方法将是通用的,不太可能适用高度特定的方法名称。因此,通常,如上所述,您的应用程序代码应为DRY,而单元测试代码为DAMP。

我希望这有助于更好地解释它。


5

我同意克里斯·爱德华兹(Chris Edwards)的观点,即您需要在两者之间取得平衡。要注意的另一件事是,如果试图删除重复项而最终在单元测试代码中添加了许多其他结构(即,将DRY发挥到极致),则冒着在其中引入错误的风险。在这种情况下,您要么必须对单元测试进行单元测试,要么不进行结构测试。


0

我不想在这里重复这些工作,但是您可以进行DAMP的测试,但可以受益于DRY。另一方面,DRY测试在某些情况下不能满足DAMP测试。

我已经写了有关DRY vs DAMP的博客,其中包括一些示例。

两种方法都不是您唯一的解决方案,有时DAMP会显得过大,有时则是非常好的选择。

作为一般规则,应应用三个规则。如果您第三次发现重复,可能值得研究编写DAMP样式测试,但是即使如此,并非所有重复都是不好的。上下文很重要。

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.