Насмешка над BlazeClientBuilder [IO] для возврата ложного клиента [IO] - PullRequest
0 голосов
/ 08 февраля 2019

Я использую метод 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)
}
}

Код вызывающего абонента

new ExternalCall(BlazeClientBuilder[IO](global).resource).retrieveData

1 Ответ

0 голосов
/ 08 февраля 2019

Кажется, вам нужно только сделать что-то вроде

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

РЕДАКТИРОВАТЬ:

Вы можете увидеть полностью рабочий пример ниже, но я хотел бы подчеркнуть, что это хорошийПример того, почему не рекомендуется использовать ложные API-интерфейсы, которыми вы не владеете.

Лучший способ проверить это - поместить связанный код http4s в принадлежащий вам класс (YourHttpClient или любой другой) и написать интеграционный тест для этого класса, который проверяет, что клиент http4s делает правильные вещи (вы можете использовать wiremock для симуляции реального http-сервера).

Затем вы можете передавать макеты YourHttpClient компонентам, которые зависят от него, с тем преимуществом, что вы контролируете его API, поэтому он будет проще, и если http4s когда-либо обновит свой API, у вас будет только один класс прерываниячем исправление десятков или сотен фиктивных взаимодействий.

Кстати, пример написан с использованием mockito-scala, так как использование версии mockito для Java привело бы к гораздо более сложному для чтения коду.

    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!!!"
...