Dowser.Client.HTTP.Stub (Dowser.Client v0.3.0)

View Source

Stubs HTTP requests in tests.

stub/1 registers a function that answers every request made by the calling process, so a test exercises the full Dowser.Client pipeline — URL building, headers, retries, JSON encoding/decoding — without a search backend running, and without Dowser.Client.HTTP ever reaching the network.

The stub is stored in the calling process: stub/1 must run in the same process that performs the request (true for a plain ExUnit test body), and each process gets its own stub with no shared/global state, so tests can run async: true. If your code makes requests from another process (e.g. a GenServer), call stub/1 from that process instead.

body, as received by the stub function, is the already-encoded request body — iodata, not necessarily a flat binary; use IO.iodata_to_binary/1 before comparing it to a string. method is the method as called, before Dowser.Client.HTTP would rewrite a GET carrying a body into a POST.

Examples

test "indexes a document" do
  Dowser.Client.HTTP.Stub.stub(fn :put, url, _headers, body, _opts ->
    assert url == "http://localhost:9200/my-index/_doc/1"
    assert IO.iodata_to_binary(body) == ~s({"title":"hello"})

    Dowser.Client.HTTP.Stub.json(201, %{"_id" => "1", "result" => "created"})
  end)

  assert {:ok, %{status: 201, body: %{"result" => "created"}}} =
           Dowser.Client.put("/my-index/_doc/1", %{title: "hello"})
end

A single stub/1 handles every request made by the process for the rest of the test; call it again to change behaviour partway through, or have the function branch on method/url to script multiple endpoints:

Dowser.Client.HTTP.Stub.stub(fn
  :get, "http://localhost:9200/my-index/_search", _headers, _body, _opts ->
    Dowser.Client.HTTP.Stub.json(200, %{"hits" => %{"hits" => []}})

  :post, "http://localhost:9200/_bulk", _headers, _body, _opts ->
    Dowser.Client.HTTP.Stub.json(200, %{"errors" => false})
end)

Summary

Functions

Removes the calling process's stub, so requests hit the network again.

Returns {:ok, fun} when the calling process has a stub registered, :error otherwise. Called by Dowser.Client.HTTP.request/5 before every request.

Builds a successful JSON response.

Builds a response with body sent as-is (a binary or iodata).

Registers fun as the stub for every request made by the calling process, replacing any previously registered stub.

Types

Functions

clear()

@spec clear() :: :ok

Removes the calling process's stub, so requests hit the network again.

fetch()

@spec fetch() :: {:ok, stub_fun()} | :error

Returns {:ok, fun} when the calling process has a stub registered, :error otherwise. Called by Dowser.Client.HTTP.request/5 before every request.

json(status, body, headers \\ [])

Builds a successful JSON response.

body is encoded with Dowser.Client.JSON, and a content-type: application/json header is added unless headers already has one.

raw(status, body \\ "", headers \\ [])

Builds a response with body sent as-is (a binary or iodata).

Use this for :raw-format requests, non-JSON responses, or to hand back malformed JSON on purpose to exercise error handling.

stub(fun)

@spec stub(stub_fun()) :: :ok

Registers fun as the stub for every request made by the calling process, replacing any previously registered stub.

fun receives the same arguments as Dowser.Client.HTTP.request/5 and must return {:ok, %Dowser.Client.Response{}} or {:error, reason}; json/3 and raw/3 build a matching response.