模拟 BlazeClientBuilder[IO] 以返回模拟客户端[IO]

Kum*_*ode 5 scala mockito io-monad scala-cats

我正在使用该BlazeClientBuilder[IO].resource方法来获取Client[IO]. 现在,我想模拟客户端进行单元测试,但不知道该怎么做。有没有一个好的方法来嘲笑这个,我会怎么做?

class ExternalCall(val resource: Resource[IO, Client[IO]], externalServiceUrl: Uri) {
def retrieveData: IO[Either[Throwable, String]] = {
for {
  req <- IO(Request[IO](Method.GET, uri = externalServiceUrl))
  response <- resource.use(client => {
    client.fetch[String](req)(httpResponse => {
      if (!httpResponse.status.isSuccess)
        throw new Exception(httpResponse.status.reason)
      else
        httpResponse.as[String]
    })
  })
} yield Right(response)
}
}
Run Code Online (Sandbox Code Playgroud)

来电代码

new ExternalCall(BlazeClientBuilder[IO](global).resource).retrieveData
Run Code Online (Sandbox Code Playgroud)

Bru*_*uno 2

看来你只需要做类似的事情

val resourceMock = mock[Resource[IO, Client[IO]]]
//stub whatever is necessary
val call = new ExternalCall(resourceMock).retrieveData
//do asserts and verifications as needed
Run Code Online (Sandbox Code Playgroud)

编辑:

您可以在下面看到一个完整的工作示例,但我想强调,这是一个很好的示例,说明了为什么避免模拟您不拥有的 API 是一个很好的做法。

测试此问题的更好方法是将 http4s 相关代码放置在您拥有的类(YourHttpClient或其他类)中,并为该类编写集成测试,以检查 http4s 客户端是否执行正确的操作(您可以使用wiremock 来模拟真实的http 服务器)。

然后,您可以将模拟传递YourHttpClient给依赖于它的组件,其优点是您可以控制其 API,因此它会更简单,并且如果 http4s 更新其 API,您只需一个破坏类,而不必修复数十或数百个模拟互动。

顺便说一句,该示例是使用mockito-scala 编写的,因为使用Java 版本的mockito 会产生更难以阅读的代码。

    val resourceMock = mock[Resource[IO, Client[IO]]]
    val clientMock   = mock[Client[IO]]
    val response: Response[IO] = Response(Status.Ok,
                                          body = Stream("Mocked!!!").through(text.utf8Encode),
                                          headers = Headers(`Content-Type`(MediaType.text.plain, Charset.`UTF-8`)))

    clientMock.fetch[String](any[Request[IO]])(*) shouldAnswer { (_: Request[IO], f: Response[IO] => IO[String]) =>
      f(response)
    }

    resourceMock.use[String](*)(*) shouldAnswer { (f: Client[IO] => IO[String]) =>
      f(clientMock)
    }

    val data = new ExternalCall(resourceMock, Uri.unsafeFromString("http://www.example.com")).retrieveData

    data.unsafeRunSync().right.value shouldBe "Mocked!!!"
Run Code Online (Sandbox Code Playgroud)