2

I'd like to test that a Http4s Client is being called from my class ClassUnderTest (to make a HTTP request) and that the request made contains the headers I expect.

In 0.18.x, I did something like below. Using a side effect to store the value of the headers so that I can make an assertion after the call. In the example below, f.execute(...) is expected to make a PUT with the client instance and I'm trying to record all request handling and storing the headers.

  "Request has headers" >> {

    var headers = List[String]()

    val client = Client[IO](new Kleisli[IO, Request[IO], DisposableResponse[IO]](request => {
      headers = request.headers.map(_.name.toString()).toList
      Ok().map(DisposableResponse(_, IO.pure(())))
    }), IO.pure(()))

    val f = ClassUnderTest(client)
    f.execute("example")

    headers must_== List(
      "Content-Type",
      "X-Forwarded-For",
      "Content-Length"
    )
  }

The real code is here if you're interested.

ClassUnderTest took a Client[IO] so I could get the above working.

class ClassUnderTest(client: http4s.Client[IO])

In Http4s 0.20.12, I had to change the signature to:

class ClassUnderTest(client: Resource[IO, http4s.Client[IO]])

...and now I can't figure out how to stub out the client for tests. I experimented with JavaNetClientBuilder but that doesn't help because I can get an instance of Client (after .create) and now I need a Resource[IO, http4s.Client[IO]].

How can I use a test double to stand in for the Client / Resource[F, Client[F]] so that I can test the requests it makes?

The testing page on the docs doesn't really help me. I want a test double, not to test all the functionality of the Service (I don't want to startup a server).

Toby
  • 9,523
  • 8
  • 36
  • 59
  • I would suggest that you should look at what a [`Resource`](https://typelevel.org/cats-effect/datatypes/resource.html) is first. Maybe you can figure something out from there. – Markus Appel Nov 05 '19 at 14:03
  • What makes you say you "had to change the signature" in that way? Using a `Resource` of a `Client` implies you are likely creating and destroying `Client`s whenever you want to use them which is expensive and inefficient. You can use `use` to do effects using a resource and, in principle, that `use` block could contain your entire program. – TheInnerLight Nov 27 '19 at 17:48
  • 1
    Try this answer https://stackoverflow.com/a/67258167/3726554 – slavik Apr 25 '21 at 20:54

0 Answers0