【问题标题】:How to mock Dispatch http client in Scala test?如何在 Scala 测试中模拟 Dispatch http 客户端?
【发布时间】:2012-01-27 20:16:25
【问题描述】:

我有一些处理 HTTP 请求的代码,我想对它进行单元测试。
因此,我试图用 Scala (2.9.1.final)、Mockito (1.9.0) 模拟 dispatch.Http 甚至更好的 dispatch.HttpExecutor (0.8.5) -rc1) 和 ScalaTest (1.6.1) 但甚至无法使我的测试代码可编译。
在 MyHttpTest 中,我想接收任何 HTTP 请求的特定 HTTP 响应:

import org.scalatest.FunSuite
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito.when
import org.mockito.Matchers.any
import dispatch._

class MyHttpTest extends FunSuite with MockitoSugar {
  test("example") {
    val httpMock = mock[HttpExecutor]
    when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_HTTP_response")
  }
}

但它会产生编译错误:

error: overloaded method value thenReturn with alternatives:
(httpMock.HttpPackage[String],<repeated...>[httpMock.HttpPackage[String]])org.mockito.stubbing.OngoingStubbing[httpMock.HttpPackage[String]] <and>
(httpMock.HttpPackage[String])org.mockito.stubbing.OngoingStubbing[httpMock.HttpPackage[String]]
cannot be applied to (java.lang.String)
when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_response")

那么如何模拟调度客户端呢?

【问题讨论】:

  • 以防万一它对某人有用 - 这是最终使用煮熟的(由 Paul Butcher)模拟的代码:println(httpMock(url("http://google.com") as_str))

标签: scala unit-testing mocking mockito scala-dispatch


【解决方案1】:

我打算用你应该尝试ScalaMock 而不是 Mockito 的建议来回答这个问题,因为我错误地认为你遇到的问题是由于 Mockito 没有真正理解 Scala(而 ScalaMock 是在 Scala 中创建的地面上)。然而:

  1. 这不是你的问题,而且
  2. 事实证明,ScalaMock 在尝试模拟 HttpExecutor 时失败,因为它不知道如何处理包对象 (ExceptionListener) 中定义的类型。该死!我会尽快修复它 - 感谢您引起我的注意。

无论如何,您不能创建HttpExecutor#HttpPackage 的实例,因为它是一个抽象类型。所以要绕过它,您需要扩展HttpExecutor 并使HttpPackage 具体化。例如:

class MyHttpTest extends FunSuite with MockitoSugar {
  trait TestHttpExecutor extends HttpExecutor {
    type HttpPackage[T] = T
  }
  test("example") {
    val httpMock = mock[TestHttpExecutor]
    when(httpMock.apply(any(classOf[Handler[String]]))).thenReturn("Some_HTTP_response")
  }
}

【讨论】:

  • 非常感谢,您的代码可以正常工作(最好是编译)!我离你的答案很近,但我不知道如何从那个 HtppPackage 中取出真正的类型(字符串)。
  • P.S.:@davidw 建议我在嘲笑它之前扩展外国课程时非常正确!
【解决方案2】:

我对 Scala 一无所知。但作为一般规则,您不应该尝试模拟不属于您自己的课程。在我看来,上面的 HttpExecutor 就是这样一个类。

对可测试性非常有效的一种模式是开发一个类,该类充当此类类的包装器,但没有自己的功能。然后编写(至少)两个单独的测试类 -

  • 您的包装类的集成测试类,以确保您是 正确调用 HttpExecutor;
  • 单元测试类,无论哪个类使用 你的包装类。

集成测试类根本不应该有任何模拟。单元测试将为您的包装类模拟。

如果我误解了你的问题 - HttpExecutor 确实是你自己的课程 - 然后再发一次,我会尝试提供不同的答案。

【讨论】:

  • 首先,你是对的,HttpExecutor - 是一个外来特征(来自调度库)。其次,我绝对同意需要集成测试——我有几个。我的愿望是也有一个纯粹的“单元”测试。但至于我——模拟外部接口/类是绝对正常的——你只是模拟一些行为,不管它是不是你的。更重要的是,在这种情况下,HttpExecutor 扩展对我没有帮助 - 因为我不明白如何描述行为本身(我尝试但得到了编译错误 =))。
  • 好吧,如果你坚持要模拟不属于你的类型。你可以自己搜索一下,找到大量的文献来解释为什么这是一个坏主意。但是,在您的特定情况下,我认为这里可能发生的情况是 HttpExecutor 的 apply() 方法返回的不是字符串,但是您正试图使其模拟返回一个字符串。 Mockito 不会让你这样做。模拟返回的值必须与该类的真实对象返回的值具有相同的类型。
  • 1.让我们省略关于嘲笑理论的讨论——因为这不是我的问题的原因。 2. 我再次同意你的观点,代码不可编译,因为 apply() 方法应该返回一些内部类型 HttpPackage[String] 但我不知道如何让 when-thenReturn 代码做到这一点。
  • 所以,你需要制作一些 HttpPackage[String] 类型的对象;然后将其作为参数传递给 thenReturn()。由于我不熟悉 Scala 或调度库,我无法建议如何构造这个对象,但这并不是关于模拟的问题。
猜你喜欢
  • 1970-01-01
  • 2011-06-13
  • 1970-01-01
  • 2020-06-06
  • 1970-01-01
  • 1970-01-01
  • 2019-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多