Packages

Mockingbird helps you create API consumers that are easy to test.

Current section

Files

Jump to
mockingbird lib mockingbird.ex
Raw

lib/mockingbird.ex

defmodule Mockingbird do
@moduledoc """
Mockingbird helps you create API consumers that are easy to test.
## Usage
# lib/my_app/github.ex
defmodule MyApp.Github do
use Mockingbird, test: MyApp.MockGithubHttpClient
def get_account_info(username) do
http_client().call(:get, "https://api.github.com/users/" <> username)
end
end
# test/support/mock_github_http_client.ex
defmodule MyApp.MockGithubHttpClient do
use Mockingbird.Client
# All the `call` methods you plan to use in tests will need a function head
# that will match test usage
def call(:get, "https://api.github.com/users/amencarini") do
respond :ok, 200, \"""
{
"login": "amencarini",
"id": 1100003
}
\"""
end
end
# test/my_app/github_test.exs
defmodule MyApp.GithubTest do
use ExUnit.Case
describe "MyApp.Github.get_account_info/1" do
test "it returns data for the selected user" do
{:ok, res} = MyApp.Github.get_account_info("amencarini")
assert Poison.decode(res.body) == %{"login" => "amencarini", "id" => 1100003}
end
end
end
## Options
use Mockingbird, test: MyApp.MockGithubHttpClient, live_client: MyApp.RealHttpClient
- `test`: specify what module will contain the mocked responses when used in
the test environment.
- `live_client`: use a custom http client for live calls. Mockingbirg comes
with a client that performs calls through HTTPoison.
"""
@doc false
defmacro __using__(opts) do
clients =
opts |> clients() |> Enum.into(%{}, fn {k, v} -> {k, Macro.expand(v, __CALLER__)} end)
quote do
@clients unquote(clients |> Macro.escape())
@default_fallback_client Mockingbird.HTTPoisonHttpClient
defp http_client do
receive do
{:force_client_env, env} ->
send(self(), {:force_client_env, env})
Map.get(@clients, env) || default_client()
after
# If the mailbox does not have a message matching as above, the
# following gets executed immediately.
0 ->
Map.get(@clients, Mix.env()) || default_client()
end
end
defmacro with_client(env, do: block) do
quote do
send(self(), {:force_client_env, unquote(env)})
unquote(block)
receive do
{:force_client_env, env} -> :ok
end
end
end
defp default_client() do
Map.get(@clients, :default_client) ||
Application.get_env(:mockingbird, :default_client, @default_fallback_client)
end
end
end
defp clients(opts) do
if Keyword.has_key?(opts, :client) do
[]
|> Keyword.put(:default_client, Keyword.get(opts, :client))
else
opts
end
end
end