【问题标题】:What does a mocking framework do for me?模拟框架对我有什么作用?
【发布时间】:2011-12-27 02:29:27
【问题描述】:

我听说一些我无法交谈的人是 jmock 的忠实粉丝。我从事以测试为中心的开发多年,所以我浏览了网站并查看了一些文档,但仍然无法弄清楚它有什么好处。

我在使用 spring 时遇到了同样的问题。如果您已经了解它是什么,他们的文档会很好地解释它,所以我不认为 jmock 没有价值。我只是不明白它对我有什么作用。

如果 jmock 为我提供了模拟存根数据的能力,那么让我们举一个例子来说明我是如何做事的,看看 jmock 会变​​得更好。

假设我的 UI 层说,为我创建一个小部件和小部件服务,在创建小部件时,初始化小部件并将其部分存储在组成小部件所需的三个表中。

当我编写测试时,我会这样做。

首先,我将 hibernate 重新指向我的测试超音速数据库,这样我就不必进行大量数据库设置了。 Hibernate 为我创建表。

我对我的类的所有测试都有静态工厂方法,它们为我构建了类的测试实例。我的每个 DAO 创建指向测试模式的测试版本。然后我的服务类有一个使用测试类生成的 DAO 构建自己的服务类。

现在,当我运行调用服务的 UI 控制器的测试时,我正在通过应用程序测试我的代码。诚然,这不是进行单元测试时通常想要的完全隔离,但在我看来,它为我提供了更好的单元测试,因为它通过所有支持层一直执行真实代码。

因为休眠状态下的 Hypersonic 速度很慢,所以运行我的所有测试需要稍长一些的时间,但我的整个构建仍然在旧计算机上运行不到五分钟即可完成构建和打包,所以我觉得这是可以接受的。

我将如何使用 jmock 做不同的事情?

【问题讨论】:

  • 您的意思是一般的模拟,或者 jmock 而不是 mockito 或 easymock 或其他什么?
  • 好吧,我对其他工具不熟悉,所以我猜一般。
  • 所以看起来模拟对象正在通过测试的工厂方法填充到我的模型中,并且测试是通过单独测试还是通过所有层来改进是一个品味问题.我理解正确吗?
  • @Thom:不完全是。这不仅仅是品味问题。集成测试有优点也有缺点。单元测试有优点也有缺点。如果你只做一个,你的测试可能没有它们应该的那么有用。

标签: java mocking


【解决方案1】:

在您的示例中,有两个接口可以使用模拟框架进行适当的单元测试:

  • UI 层和小部件服务之间的接口 - 用模拟替换小部件服务将允许您单独测试 UI 层,服务返回手动创建的数据,模拟验证预期的服务调用(以及没有其他)发生。
  • 小部件服务和 DAO 之间的接口 - 通过将 DAO 替换为 mock,任何包含复杂逻辑的服务方法都可以单独测试。

当然,这不是进行单元测试时通常需要的完全隔离,但在我看来,它为我提供了更好的单元测试,因为它通过所有支持层一直执行真实代码。

这似乎是您问题的核心。答案有很多方面:

  • 如果您不单独测试组件,那么您就没有单元测试,而是有集成测试。正如您所观察到的,它们非常有价值,但它们也有其缺点
  • 由于他们同时测试更多的东西,他们往往会更频繁地中断,他们往往会在大组中中断(当常见功能出现问题时),当他们这样做时,更难找出实际发生在哪里问题出在
  • 它们在您可以测试的场景类型方面受到更多限制。在集成测试中模拟某些边缘情况可能很难或不可能。
  • 有时无法自动化完整的集成测试,因为您无法充分控制某些组件(例如第三方 Web 服务)来设置您需要的测试数据。在这种情况下,您甚至可能最终在高级集成测试中使用模拟框架。

【讨论】:

  • 谢谢,我现在明白了。我现在必须考虑一下。
  • “由于他们同时测试更多的东西,他们往往会更频繁地中断,他们倾向于在大组中中断(当常见功能出现问题时),当他们这样做时,更难找出实际问题出在哪里”另一方面,它可能只在一个地方中断,因为特定测试以我在根测试中错过的方式使用该类。我和其他人一起经历过这种情况。这方面有很多思考要做。再次感谢您的意见。
  • @Thom:你说得对——有些错误只能通过集成测试才能捕捉到,因为它们是集成错误(即组件连接和交互的方式)。
【解决方案2】:

我没有特别关注 JMock(我使用 Mockito),但一般来说,模拟框架允许您“模拟”外部服务,这样您一次只需要测试一个类。可以模拟该类的任何依赖项,这意味着不会进行真正的方法调用,而是调用返回或抛出常量的存根。这是一件好事,因为外部调用可能很慢、不一致或不可靠——这对单元测试来说都是坏事。

举一个例子来说明这是如何工作的,假设您有一个依赖于 Web 服务客户端的服务类。如果您使用真正的 Web 服务客户端进行测试,它可能会关闭,连接可能会很慢,或者 Web 服务背后的数据可能会随着时间而改变。您将如何针对此编写可靠的测试? (你不能)。因此,您使用模拟框架来模拟/存根 Web 服务客户端,并创建假响应、假错误、假异常,以模仿 Web 服务行为。不同之处在于结果总是快速且一致的。

此外,您希望测试给定依赖项可能存在的所有失败案例,但不进行模拟很难做到。考虑我上面给出的例子。如果 Web 服务由于 Web 服务关闭(或超时)而引发 IOException,您希望确保您的代码执行正确的操作,但强制这种情况并不容易。通过模拟,这变得微不足道。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多