Skip to content

Instantly share code, notes, and snippets.

@tiagopog
Last active August 28, 2019 16:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tiagopog/d4edf68045c7f44ab89e7044570eb836 to your computer and use it in GitHub Desktop.
Save tiagopog/d4edf68045c7f44ab89e7044570eb836 to your computer and use it in GitHub Desktop.
Elixir - Ways of using test mocks
##
# Implementation
##
# config/config.exs
config :my_app, :kv_store_adapter, KVStore
defmodule KVStore do
#...
end
defmodule Persist do
@adapter Application.get_env(:my_app, :kv_store_adapter)
def write_all(params) when is_map(params) do
Enum.each(params, fn {k, v} -> @adapter.write(k, v) end)
end
def read_all(keys) when is_list(keys) do
Enum.map(keys, &@adapter.read/1)
end
end
##
# Tests
##
# config/test.exs
config :my_app, :kv_store_adapter, KVStoreTest
defmodule KVStoreTest do
#...
end
defmodule PersistTest do
use ExUnit.Case, async: true
describe "write_all/2" do
test "sends the correct message to our KV store for each key/value pair" do
Persist.write_all(%{key: :value, key2: :value2})
assert_receive({:write, {:key, :value}})
assert_receive({:write, {:key2, :value2}})
end
end
describe "read_all/2" do
test "returns a list of values for the given keys" do
assert Persist.read([:key, :key2]) == [{:read, :key}, {:read, :key2}]
end
end
end
##
# Implementation
##
defmodule KVStore do
use GenServer
def start_link(_) do
GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
end
def write(key, value) do
GenServer.cast(__MODULE__, {:write, key, value})
end
def read(key) do
GenServer.call(__MODULE__, {:read, key})
end
def handle_cast({:write, key, value}, state) do
{:noreply, Map.put(state, key, value)}
end
def handle_call({:read, key}, _, state) do
{:reply, Map.get(state, key), state}
end
end
defmodule Persist do
def write_all(params, kvstore \\ KVStore) when is_map(params) do
Enum.each(params, fn {k, v} -> kvstore.write(k, v) end)
end
def read_all(keys, kvstore \\ KVStore) when is_list(keys) do
Enum.map(keys, &kvstore.read/1)
end
end
##
# Tests
##
defmodule PersistTest do
use ExUnit.Case, async: true
defmodule KVStore do
def write(key, value), do: send(self(), {:write, {key, value}})
def read(key), do: {:read, key}
end
describe "write_all/2" do
test "sends the correct message to our KV store for each key/value pair" do
Persist.write_all(%{key: :value, key2: :value2}, KVStore)
assert_receive({:write, {:key, :value}})
assert_receive({:write, {:key2, :value2}})
end
end
describe "read_all/2" do
test "returns a list of values for the given keys" do
assert Persist.read([:key, :key2], KVStore) == [{:read, :key}, {:read, :key2}]
end
end
end
# See: https://hexdocs.pm/mox/Mox.html
##
# Implementation
##
def deps do
[
{:mox, "~> 0.5", only: :test}
]
end
defmodule MyApp.Calculator do
@callback add(integer(), integer()) :: integer()
@callback mult(integer(), integer()) :: integer()
end
##
# Tests
##
# test_helper.exs:
Mox.defmock(MyApp.CalcMock, for: MyApp.Calculator)
use ExUnit.Case, async: true
import Mox
# Make sure mocks are verified when the test exits
setup :verify_on_exit!
test "invokes add and mult" do
MyApp.CalcMock
|> expect(:add, fn x, y -> x + y end)
|> expect(:mult, fn x, y -> x * y end)
assert MyApp.CalcMock.add(2, 3) == 5
assert MyApp.CalcMock.mult(2, 3) == 6
end
# See: https://github.com/edgurgel/mimic
##
# Implementation
##
defmodule MyApp.External.API.Request do
defstruct api_version: nil
def get(%Request{} = request) do
# call `HTTPoison.get/3` at some point here...
end
end
##
# Tests
##
# test_helper.exs
Mimic.copy(HTTPoison)
ExUnit.start()
# test/external/api/request_test.exs
defmodule MyApp.External.API.RequestTest do
use ExUnit.Case, async: true
use Mimic
alias MyApp.External.API.Request
@decoder Jason
doctest Request
describe "get/1" do
test "successful call to some external API" do
response_body = %{"foo" => "bar"}
HTTPoison
|> expect(:get, fn _url, _headers, _options ->
body = @decoder.encode!(response_body)
response = %HTTPoison.Response{status_code: 200, body: body}
{:ok, response}
end)
result = %Request{api_version: "v1"} |> Request.get()
assert result == {:ok, response_body}
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment