Java 在JUnit测试中模拟对象-最佳实践?

Java 在JUnit测试中模拟对象-最佳实践?,java,junit,mocking,Java,Junit,Mocking,您认为在JUnit测试中模拟对象是最佳实践吗?我看不出有什么好处。当然,如果您有一个不应该在测试中考虑的数据库,那么它是有意义的,但是为什么不只是注入该组件的另一个实现(如果使用了spring)。测试的对象工厂将使这变得非常容易。我没有太多的经验(我们正在使用Mockito),但我已经看到,应用程序代码会被修改,从而使一些属性变得可模仿!在我的观点中,测试用例永远不应该忽视生产代码中的这种变化 你觉得这个话题怎么样?在哪种情况下,您是在模拟对象还是为什么不模拟对象?模拟的思想是完全隔离您正在测试

您认为在JUnit测试中模拟对象是最佳实践吗?我看不出有什么好处。当然,如果您有一个不应该在测试中考虑的数据库,那么它是有意义的,但是为什么不只是注入该组件的另一个实现(如果使用了spring)。测试的对象工厂将使这变得非常容易。我没有太多的经验(我们正在使用Mockito),但我已经看到,应用程序代码会被修改,从而使一些属性变得可模仿!在我的观点中,测试用例永远不应该忽视生产代码中的这种变化


你觉得这个话题怎么样?在哪种情况下,您是在模拟对象还是为什么不模拟对象?

模拟的思想是完全隔离您正在测试的对象。然后,当测试失败时,您可以确定问题在哪里,而不必搜索整个类依赖关系树。如果您同时测试多个类的行为,那么这不是真正的单元测试

用于测试的对象工厂可能会使用方法生成对象,而框架本质上是用于测试的通用对象工厂。但是mock提供的比stub提供的多得多——Martin Fowler在这里详细介绍了这一区别:

如果你觉得模仿很难,而且你也发现你做了很多,那么这就是TDD的一个经典例子,告诉你你的设计可以改进

我已经看过了,那个应用程序 对代码进行修改,以便 属性变得可模仿!测试用例 我们决不应忽视这些变化 在我的业务中使用高效代码

TDD的核心思想是,通过强制您使所有代码都可测试,总体设计将变得更好。这并不一定意味着一切都可以模拟,还可能意味着减少耦合,从而减少模拟的必要性

即使您不同意这一理念(我自己也不完全相信),只要您相信自动化测试提供了价值,那么更改生产代码以支持该价值是有意义的(除非它以其他方式严重损害了设计)。

  • 定义校准类接口(接口发现)
  • 允许从上到下的设计
  • 隔离(单元测试)
  • 澄清类之间的交互
  • 有时,查看对象是否符合您的要求的唯一方法()
  • 鼓励更好的结构化测试。例如,auto注入mock使您能够专注于需要测试的东西
  • 允许保留封装
  • 减少依赖性

  • 不应模拟值对象

出于必要而嘲笑框架。正如Matthew Gilliard所说,如果存在某种嘲弄,那么这就是设计可以改进或缺乏测试重点的迹象。测试揭示了代码中的许多问题

但为什么不注入该组件的另一个实现(如果使用了spring的话)

您必须编写实现。使用模拟框架,它是为您完成的

我已经看到,应用程序代码得到了修改,使一些属性变得可模仿!在我看来,测试用例不应该在生产代码中进行这样的更改


如果mockable意味着可测试,那么情况正好相反。例如,在TDD中,测试定义了生产代码。

我认为真正的问题是单元测试是否是最佳实践。如果您认为是这样,那么从将测试单元与其依赖项的实现隔离开来的角度来看,使用模拟是必要的

然而,这与可测试性概念之间的关系存在一些混乱。复杂的卷积代码本质上是不可测试的,因为它很难理解。设计简洁简洁的代码通常更容易理解和维护;那么,为什么单元测试很难呢

混淆源于某些模拟工具中的某些任意限制,例如无法模拟
final
static
方法,或者需要被测试单元直接使用在测试代码中创建的模拟对象。其他模拟工具没有这些限制,因此不要求“修改应用程序代码以使某些属性可模拟”。有了现代编程语言/平台(Java、C#、Python、Ruby等),一切都是可模仿的;这只是一个在模拟API中公开此功能的问题,并且已经为每种语言完成了(为了充分公开,我开发了一个这样的工具)