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.0.1"}]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 :("
endUsing 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
endAnd 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
Wrapping HTTPlacebo.Base
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
endFor 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
endAnd 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.InMemoryClientIt'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_codeLicense
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.