unit testing反模式目录

反模式 :必须存在至less两个关键要素才能正式区分实际的反模式和简单的坏习惯,不好的做法或坏主意:

  • 一些重复的行为,过程或结构模式最初似乎是有益的,但最终会产生比有益结果更糟糕的后果
  • 重构的解决scheme清晰logging,在实践中得到validation并可重复使用。

投票你曾经看过“野外”的TDD反模式太多了。
詹姆斯·卡尔的博客文章和关于testing驱动yahoogroup的相关讨论

如果你find了一个“未命名”的人,也可以发帖。 每个反模式的一个职位,请投票的东西。

我的既得利益是find前n个子集,以便我可以在不久的将来在饭盒会议上讨论他们。

二级公民 – testing代码不像生产代码那样重构,包含大量重复的代码,因此很难保持testing。

免费乘车/搭载 – 詹姆斯·卡尔,蒂姆·奥廷格
与其写一个新的testing用例方法来testing另一个/独特的特性/function ,一个新的断言(及其相应的动作,即从AAA执行的Act步骤)在现有的testing用例中进行。

快乐的path

testing保持愉快的path(即预期的结果),没有testing边界和例外。

JUnit反模式

当地的英雄

testing用例依赖于为了运行而编写的开发环境特定的东西。 结果是testing通过了开发框,但当有人试图在别处运行时失败。

隐藏的依赖

与当地英雄密切相关,unit testing需要在testing运行之前将某些现有数据填充到某处。 如果这些数据没有填充,testing将会失败,并且不会给开发者什么想要的东西,或者为什么…迫使他们挖掘大量的代码来找出它使用的数据应该来自哪里。


不幸的是,古代的.dll太多了,而这些文件依赖于任何生产系统中不断同步的模糊不清的.ini文件,更不用说与三位负责这些DLL的开发人员的广泛协商了。 叹。

链钢

一些testing必须以特定顺序运行,即一个testing改变系统的全局状态(全局variables,数据库中的数据)和下一个testing依赖于它。

你经常在数据库testing中看到这个。 而不是在teardown()中进行回滚,testing会将其更改提交到数据库。 另一个常见的原因是全局状态的改变没有包含在try / finally块中,如果testing失败,这些块将被清除。

嘲弄
有时嘲笑可以很好,方便。 但有时开发者可能会失去自己,努力去模拟没有被testing的东西。 在这种情况下,unit testing包含了太多的模拟,存根和/或伪造,所以被测系统甚至没有被testing,而是从模拟模块返回的数据是被testing的。

资料来源:詹姆斯·卡尔的职位。

沉默的捕手 – 凯利?
一个testing,如果抛出exception,即使实际发生的exception是一个不同于开发人员的意图。
另请参阅: 秘密守望者

 [Test] [ExpectedException(typeof(Exception))] public void ItShouldThrowDivideByZeroException() { // some code that throws another exception yet passes the test } 

督察
为了达到100%的代码覆盖率,一个unit testing为了达到100%的代码覆盖率,但是知道如此多的事情,任何重构的尝试都会打破现有的testing,并要求在unit testing中反映任何变化。


“我怎么testing我的成员variables而不公开它们…… 只是为了unit testing?

过度安置 – 詹姆斯·卡尔
一个testing,需要一个巨大的设置,以便开始testing。 有时候,有几百行代码被用来为一个testing准备环境,涉及到几个对象,这使得很难真正确定由于所有设置的“噪声”而进行的testing。 (Src: 詹姆斯·卡尔的职位 )

肛门探头

一个testing必须使用疯狂,非法或其他不健康的方式来执行其任务,如:使用Java的setAccessible(true)读取私有字段,或者扩展一个类来访问受保护的字段/方法,或者必须将testing放在特定的包中才能访问打包全局字段/方法。

如果你看到这个模式,被testing的类就会使用太多的数据隐藏。

这和Inspector之间的区别在于,被testing的类会试图隐藏你需要testing的东西。 所以你的目标不是要达到100%的testing覆盖率,而是要能够testing任何东西。 想想一个只有私有字段的类,一个没有参数的run()方法,根本就没有getter。 没有办法在不违反规定的情况下进行testing。


Michael Borgwardt评论: 这不是一个真正的testing反模式,它是处理被测代码缺陷的实用主义。 当然,最好是解决这些不足之处,但在第三方库的情况下可能是不可能的。

Aaron Digulla:我有点同意。 也许这个条目更适合于“JUnit HOWTO”wiki,而不是反模式。 注释?

没有名字的testing – Nick Pellow

在bug追踪器中重新生成一个特定的bug并且作者认为不能保证自己的名字的testing。 而不是增强现有的,缺乏testing,创build一个新的testing称为testForBUG123。

两年后,当testing失败时,您可能需要首先尝试在错误跟踪器中findBUG-123,以确定testing的意图。

慢戳

运行速度非常慢的unit testing。 当开发商启动它们时,他们有时间去洗手间,抽烟,或者更糟糕的是,在他们回家之前踢完testing。 (Src: 詹姆斯·卡尔的post )

也就是说不能像他们应该那样经常运行的testing

蝴蝶

你必须testing一些包含一直改变的数据的东西,比如一个包含当前date的结构,而且没有办法将结果固定到一个固定的值。 丑陋的部分是,你根本不在乎这个价值。 它只是让你的testing更加复杂,不增加任何价值。

它的翅膀的蝙蝠可能会导致世界另一端的飓风。 – 爱德华洛伦兹, 蝴蝶效应

闪烁testing (来源:Romilly Cocking)

一个只是偶尔失败的testing,而不是在特定的时间,通常是由于testing中的种族条件。 通常在testingasynchronous的东西时发生,比如JMS。

可能是超级设置为“ 等待看 ”的反模式和“ The Sleeper ”反模式。

构build失败,哦,只需再次运行构build。 – 匿名开发者

等着瞧

一个testing运行一些设置的代码,然后需要“等待”一段特定的时间,才能“看到”被testing代码是否按预期工作。 使用Thread.sleep()或等效的testMethod肯定是一个“等待看”testing。

通常情况下,如果testing正在testing生成系统外部事件的代码(如电子邮件,http请求或将文件写入磁盘),则可能会看到此情况。

这样的testing也可能是一个本地英雄,因为它会在一个较慢的盒子或一个超载的CI服务器上运行时失败。

Wait and See反模式不要与The Sleeper混淆。

不适当的共享夹具 – Tim Ottinger
testing夹具中的几个testing用例甚至不使用或不需要安装/拆卸。 部分原因是由于开发人员的惯性,创build一个新的testing夹具…更容易只是添加一个testing用例堆

巨人

unit testing虽然可以有效地testing被测对象,但可以覆盖数千行,并包含许多testing用例。 这可以表示被testing的系统是上帝对象 (James Carr's post)。

这一个肯定的标志是跨越几行代码的testing。 通常情况下,testing是如此复杂,以至于它开始包含自己的或片状行为的错误。

当我看到一些闪烁的GUI时,我会相信它
一个不健康的固定/痴迷与通过它的GUItesting应用程序“就像一个真正的用户”

通过GUItesting业务规则是一种可怕的耦合forms。 如果通过GUI编写数千个testing,然后更改GUI,则会有数千个testing中断。
而是通过graphics用户界面(GUI)testinggraphics用户界面(GUI),并在运行这些testing时将graphics用户界面(GUI)与虚拟系统(而不是真实的系统)耦合。 通过不涉及GUI的APItesting业务规则。 – 鲍勃·马丁

“你必须明白,眼见为实,但也知道眼见为实。” – 丹尼斯·维特利

Sleeper,又名维苏威火山 – Nick Pellow

在未来某个特定时间和date注定要失败的testing。 当testing使用Date或Calendar对象的代码时,这通常是由不正确的边界检查引起的。 有时,如果在一天的特定时间(如午夜)运行,testing可能会失败。

“睡梦者”不要与“ 等待看 ”的反模式混淆。

这个代码早在2000之前就已经被replace了 – 许多开发者在1960年

死树

一个testing,其中创build一个存根,但testing没有实际写入。

我已经在生产代码中看到了这一点:

 class TD_SomeClass { public void testAdd() { assertEquals(1+1, 2); } } 

我甚至不知道该怎么想。

今天得到了这个:

湿地板
testing会创build在某处保存的数据,但testing完成后不会清理。 这会导致testing(相同的testing或可能的其他testing)在随后的testing运行中失败。

在我们的例子中,testing在第一次运行testing的用户的权限下留下了一个位于“temp”目录的文件。 当一个不同的用户试图在同一台机器上testing:繁荣。 在对詹姆斯·卡尔的网站的评论中,乔金·奥尔格格(Joakim Ohlrogge)将此称为“Sl Worker的工人”,这是“慷慨残羹”的灵感的一部分。 我更喜欢我的名字(不那么侮辱,更熟悉)。

杜鹃 – 弗兰克·卡弗
一个unit testing,与其他几个testing用例一样,并且与testing用例中的其他testing一样享有相同的(可能冗长的)设置过程,但是丢弃设置中的一些或全部工件并创build它自己的。
高级症状: 不适当的共享夹具

秘密守望者 – 弗兰克·卡弗
由于缺乏断言,乍一看似乎没有进行testing。 但是“魔鬼在细节中”..testing实际上是依靠抛出的exception,期待testing框架捕获exception并将其作为失败报告给用户。

 [Test] public void ShouldNotThrow() { DoSomethingThatShouldNotThrowAnException(); } 

环境破坏

针对各种“要求”开始向其环境中溢出的“单元”testing,使用和设置环境variables/端口。 同时运行这两个testing会导致“不可用的端口”exception等。

这些testing将是间歇性的,让开发人员说“再次运行”。

我看到的一个解决scheme是随机select一个端口号来使用。 这减less了冲突的可能性,但显然不能解决问题。 所以,如果可以的话,总是嘲笑代码,以便它实际上不分配不可用资源。

图灵testing

一个由一些昂贵的工具自动生成的testing用例,它使用一些太巧妙的数据stream分析从被testing的类中搜集到许多断言。 让开发人员误以为自己的代码经过了充分的testing,从而免除了devise和维护高质量testing的责任。 如果机器可以为你写testing,为什么不能把手指伸出来写出应用程序呢!

你好傻。 – 世界上最聪明的电脑新学徒(从一个老的Amiga漫画)。

四十脚testing

由于怕太靠近自己正在testing的类,所以这些testing远远地行动起来,被无数的抽象层和数千行代码从他们正在检查的逻辑中分离出来。 因此,它们非常脆弱,容易受到兴趣阶层史诗旅程中发生的种种副作用的影响。

分身

为了testing某些东西,你必须将被测代码的一部分复制到一个具有相同名称和包的新类中,并且必须使用类path魔法或自定义类加载器来确保它首先可见(所以你的副本被拾取向上)。

这种模式表明一个不健康的隐藏的依赖关系,你无法从testing中控制。

我看着他的脸……我的脸! 它就像一面镜子,但却让我的血液冻结了。

母鸡 – 弗兰克·卡弗
远远超过实际testing用例需要的常见设置。 例如创build各种复杂的数据结构,当testing仅仅表明存在或不存在某些东西时,这些复杂的数据结构就会显示出明显重要且独特的值。
高级症状: 不适当的共享夹具

我不知道它是什么…无论如何我都加了,以防万一。 – 匿名开发者

testing一切

我不敢相信这到目前为止还没有提到,但是testing不应该违背单一责任原则

我遇到过这么多次,打破这个规则的testing在定义上是一个噩梦来维护。

线击球员

On the first look tests covers everything and code coverage tools confirms it with 100%, but in reality tests only hit code without any output analyses.

coverage-vs-reachable-code