你应该只嘲笑你拥有的types吗?

我通过TDD阅读:只有马克·李约翰(Mark Needham) 拥有的模拟types ,想知道这是否是最佳实践?

请注意,他并不反对嘲笑,而是直接嘲笑 – 他确实说过写一个包装,嘲笑这很好。

取决于你的意思是模拟或模拟™…

考虑到你只是使用模拟框架(如Mockito)来创build存根,那么创build不属于你的types的存根是完全合理的。

但是,如果你正在使用模拟框架(如Mockito)来创build模拟对象,那么你最好遵循模拟传道者的build议。 我个人对这个运动失去了联系,所以我不能告诉你李察的build议是否被认为是犹太教的。

讽刺的是,Mark写的关于Hibernate EntityManagers嘲讽本身听起来很合理。 但是我怀疑,我们可以从这个具体案例中总结出一个规则,比如“不要模仿你不拥有的types”。 有时它可能是有道理的,有时不是。

我的答案是“不”。 你应该在给定的unit testing的背景下嘲笑任何有意义的东西。 如果你“拥有”嘲笑的types,这应该不重要。

现在,在Java或者.NET环境中,所有的事情(我真正意义上的一切)都可以轻易地被嘲弄。 所以,没有任何技术上的理由要去写第一个写额外的包装代码的麻烦。


我最近一直在想的还有一些其他的想法(2010年11月),这些想法表明“仅仅嘲笑你自己的types”是不合逻辑的:

  1. 假设你为第三方API创build了一个包装器,然后你在unit testing中模拟包装器。 然而,后来,你认为包装可以在另一个应用程序重用,所以你把它移动到一个单独的库。 所以现在包装器不再是你所拥有的(因为它被用于多个应用程序,可能由不同的团队维护)。 开发者是否应该为旧的创build一个新的包装? 并继续做recursion,添加本质上无用的代码层?
  2. 假设其他人已经为一些非平凡的API创build了一个漂亮的包装,并将其作为可重用的库提供。 如果所说的包装器就是我需要的特定用例,那么我是否应该首先为包装器创build一个封装器,使用几乎相同的API,这样我就可以“拥有”它了!

对于一个具体而实际的例子,可以考虑Apache Commons Email API,它只不过是标准Java Mail API的包装器。 因为我不拥有它,所以每当我为需要发送电子邮件的类编写unit testing时,是否应该总是为Commons Email API创build一个包装?

我喜欢Mockito项目给这个问题的解释 。

不要模拟你不拥有的types!

这不是一个强硬的路线,但穿越这条线可能会产生影响! (很可能会)

  1. 想象一下嘲笑第三方库的代码。 在第三个库的特定升级之后,逻辑可能会改变一点,但是testing套件将会执行得很好,因为它被嘲笑了。 所以,以后想,一切都好,build筑墙壁毕竟是绿色的,软件部署和…兴旺
  2. 这可能是一个标志,目前的devise是不是从这个第三方库足够脱钩。
  3. 另一个问题是,第三方库可能是复杂的,需要大量的模拟才能正常工作。 这导致过度指定的testing和复杂的装置,这本身就危及紧凑和可读的目标。 或者因为testing不足以覆盖代码,因为模拟外部系统的复杂性。

相反,最常用的方法是在外部库/系统周围创build包装,尽pipe应该意识到抽象泄漏的风险,即过多的低级API,概念或exception超出了包装的边界。 为了validation与第三方库的集成,编写集成testing,并使其尽可能紧凑和可读。

我打算说“不”,但是看了一下博客文章,我可以看到他在说什么。

他专门讲述了在Hibernate中嘲笑EntityManagers。 我反对这个。 EntityManagers应该隐藏在DAO(或类似的)中,DAO应该被嘲笑。 testing一行调用EntityManager是一个完全浪费你的时间,只要有任何改变就会中断。

但是,如果你有第三方代码,你想testing你如何与之交互,一切手段。

我当然是来​​自less数,但我认为Mocking是一种代码嗅觉,如果可能的话,使用dependency injection。 理由是嘲笑基本上是testing一些难以testing代码的解决方法。 嘲笑削弱了testing,因为他们的行为(充其量)就像一个图书馆的特定版本。 如果图书馆改变了,你的testing就会松动所有的检查值。

你可以看看我正在使用Mark Needham自己的论点,但不是说你不应该嘲笑你不拥有的对象,但是你不应该模拟

好的,如果dependency injection不是一个选项,那么让我们来嘲笑…但是你必须明白你的testing是假的,不会像生产代码那样工作。 这不是一个真正的unit testing,只是一个假的。 如果可能的话,可以通过添加testing来检查行为是否符合Mocked Objects的预期。

我同意马克的意思。 你不能不幸嘲笑一切,有些东西你不想嘲笑,只是因为你正常使用它是一个黑匣子。

我的经验法则是模拟将使testing快速但不会使testing片状的东西。 记住并非所有的假货都是一样的, 嘲笑不是存根 。