HTTPlacebo
HTTP client mocking tool for Elixir, based on HTTPotion, HTTPoison and inspired in HTTPretty.
Installation
-
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
Usage
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
Using with existing applications
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
HTTPlacebo.Base
Wrapping 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
License
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.