我通过Mark Needham的TDD: Only mock types you own条目阅读并想知道这是否是最佳做法?
请注意,他不是反对嘲笑,而是直接反对嘲笑 - 他确实说过写一个包装并嘲笑这很好。
答案 0 :(得分:28)
我的回答是“不”。你应该在给定单元测试的上下文中模拟任何有意义的东西。如果你“拥有”模拟类型,那应该没关系。
现在,在Java或.NET环境中,一切(我真的意味着一切)都可以很容易地被嘲笑。因此,没有技术上的理由去首先编写额外的包装代码。
我最近(2010年11月)一直在思考的其他一些想法,表明“只有你自己的模拟类型”的不合逻辑可能是:
对于具体而实际的示例,请考虑Apache Commons Email API,它只不过是标准Java Mail API的包装器。由于我不拥有它,每当我为需要发送电子邮件的类编写单元测试时,我是否应该始终为Commons Email API创建一个包装器?
答案 1 :(得分:22)
取决于你是否意味着模拟或模拟......
鉴于您只是使用模拟框架(例如Mockito)来创建存根,那么创建您不拥有的类型的存根是完全可以合理的。
但是,如果您使用模拟框架(例如Mockito)来创建mock™对象,那么您最好遵循mock™布道者的建议。就个人而言,我对这一运动失去了联系,所以我无法告诉你Mark Needham的建议是否被视为犹太教。
除此之外,马克写的关于在Hibernate中嘲笑EntityManagers
的内容听起来本身就是合理的。但是我怀疑我们可以从这个特定的案例中概括出一个像“永远不会嘲笑你不拥有的类型”这样的规则。有时它可能有意义,有时不是。
答案 2 :(得分:14)
我喜欢这个问题的explanation the Mockito project gives。
不要嘲笑你不拥有的类型!
这不是一条强硬路线,但越过这条线可能会有 反响! (很可能会)
- 想象一下嘲笑第三方lib的代码。在第三个库的特定升级之后,逻辑可能会改变一点,但是测试 套件将执行得很好,因为它被嘲笑。所以后来, 认为一切都很好,毕竟建筑墙是绿色的, 该软件已部署并...... Boom
- 这可能表示当前设计与第三方库没有足够的分离。
- 另一个问题是第三方lib可能很复杂,需要很多模拟才能正常工作。这导致过度 指定的测试和复杂的固定装置,这本身就妥协了 紧凑和可读的目标。或者不包含代码的测试 因为模拟外部系统的复杂性。
醇>相反,最常见的方法是在外部创建包装器 lib / system,尽管应该知道抽象的风险 泄漏,过多的低级API,概念或例外 超出包装器的边界。为了验证集成 与第三方库,编写集成测试,并制作它们 尽可能紧凑和可读。
答案 3 :(得分:8)
我打算说“不”,但快速浏览一下博文,我可以看到他的内容。
他特别谈到在Hibernate中模拟EntityManagers。我反对这个。 EntityManagers应该隐藏在DAO(或类似的)中,DAO应该被嘲笑。测试一行调用EntityManager完全浪费你的时间,一旦发生任何变化就会中断。
但是,如果你确实有第三方代码,你想测试你如何与它进行交互。
答案 4 :(得分:1)
相关问题是耦合之一,即您的测试代码指定了什么。您当然不希望测试代码指定您碰巧使用的某些库的API的详细信息。这是你得到的,例如使用Mockito直接在您的测试类中模拟库。
这个问题的widespread solution proposal是围绕库创建一个包装器然后模拟包装器。但这有以下缺点:
相反,我建议将生产代码中的接口与测试完全分离。不要直接将模拟放入测试代码中,而是创建一个单独的存根类来实现或模拟生产界面。然后向存根添加第二个接口,允许测试执行必要的设置或断言。然后,您只需要调整一个类,以防生产界面发生变化 - 您甚至可以模拟/存储复杂或频繁更改的库的接口。
注意:所有这些都假设实际上必须使用模拟或存根。我这里没有讨论这个问题,因为它不在OP的问题范围内。但是真的问问自己是否必须使用模拟/存根。根据我的经验,他们被过度使用......
答案 5 :(得分:0)
我同意马克的说法。你不能不幸地嘲笑一切,有些东西你不想嘲笑,只因为你正常使用它是一个黑盒子。
我的经验法则是模拟可以使测试快速但不会使测试变薄的事情。请记住,并非所有假货都是相同的Mocks are not Stubs。
答案 6 :(得分:0)
我当然是少数人,但我认为Mocking是一个代码嗅觉并且如果可能的话使用依赖注入。理由是,模拟基本上是测试一些难以测试的代码的解决方法。模拟会削弱测试,因为它们(最好)像特定版本的库一样。如果库发生了变化,那么您的测试将失去所有检查值。
你可以看到上面的内容,我正在使用马克·李约瑟自己的论点,但不是因为你说你不应该嘲笑你不拥有的对象,而是你不应该嘲笑......
好吧,如果依赖注入不是一个选项,那么让我们模拟......但是你必须明白你的测试是假的,并且不会像生产代码那样。这不是一个真正的单元测试,只是一个部分伪造的测试。如果可能的话,你可以通过添加检查行为与模拟对象一样的行为的测试来减少它。