HTTP client mocking tool for Elixir, based on HTTPotion, HTTPoison and inspired in HTTPretty.
-
Add httplacebo to your list of dependencies in
mix.exs
:def deps do [{:httplacebo, "~> 0.1.0"}] end
-
Ensure httplacebo is started before your application:
def application do [applications: [:httplacebo]] end
iex> HTTPlacebo.start
iex> HTTPlacebo.register_uri(:get, "http://localhost:3000/posts/1", [body: ~s({"post": {"title": "First Post"}}), headers: [{"Content-Type", "application/json"}]])
iex> HTTPlacebo.get! "http://localhost:3000/posts/1"
%HTTPlacebo.Response{
body: "{\"post\": {\"title\": \"First Post\"}}",
headers: [{"Content-Type", "application/json"}],
status_code: 200
}
iex> HTTPlacebo.get! "http://localhost:3000/users"
%HTTPlacebo.Response{body: "Not Found", status_code: 404}
iex> HTTPlacebo.get "http://localhost:3000/users"
{:ok, %HTTPlacebo.Response{body: "Not Found", status_code: 404}}
You can also easily pattern match on the HTTPlacebo.Response
struct:
case HTTPlacebo.get(url) do
{:ok, %HTTPlacebo.Response{status_code: 200, body: body}} ->
IO.puts body
{:ok, %HTTPlacebo.Response{status_code: 404}} ->
IO.puts "Not found :("
end
You can use HTTPlacebo as replacement for HTTPoison instead of mocking as described in the Mocks and Explicit contracts post by Jose Valim.
defmodule MyBlog.Post do
@http_mod Application.get_env(:my_app, :http_mod)
def get(id) do
# ...
@http_mod.get("http://myblog.com/posts/" <> id)
# ...
end
end
And now we can configure it per environment as:
# In config/dev.exs
config :my_app, :http_mod, HTTPoison
# In config/test.exs
config :my_app, :http_mod, HTTPlacebo
You can also use the HTTPlacebo.Base
module in your test modules in order to
make cool API clients or something.
The following example wraps HTTPoison.Base
in order to build a client for the GitHub API
(Poison is used for JSON decoding):
defmodule GitHub.Client do
use HTTPoison.Base
def process_url(url) do
"https://api.github.com" <> url
end
def process_response_body(body) do
body
|> Poison.decode!
|> Enum.map(fn({k, v}) -> {String.to_atom(k), v} end)
end
end
For your tests you can create a test module similarly:
defmodule GitHub.InMemoryClient do
use HTTPlacebo.Base
def process_url(url) do
"https://api.github.com" <> url
end
def process_response_body(body) do
body
|> Poison.decode!
|> Enum.map(fn({k, v}) -> {String.to_atom(k), v} end)
end
end
And now we can configure it per environment as:
# In config/dev.exs
config :my_app, :github_client, GitHub.Client
# In config/test.exs
config :my_app, :github_client, GitHub.InMemoryClient
It's possible to extend the functions listed below:
defp process_request_body(body), do: body
defp process_response_body(body), do: body
defp process_request_headers(headers) when is_map(headers) do
Enum.into(headers, [])
end
defp process_request_headers(headers), do: headers
defp process_response_chunk(chunk), do: chunk
defp process_headers(headers), do: headers
defp process_status_code(status_code), do: status_code
Copyright © 2016 Guillermo Iguaran <guilleiguaran@gmail.com>
This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the LICENSE file for more details.