Packages
espec
1.6.0
1.10.0
1.9.2
1.9.1
1.9.0
1.8.3
1.8.2
1.8.1
1.8.0
1.7.0
1.6.5
1.6.4
1.6.3
1.6.2
1.6.1
1.6.0
1.5.1
1.5.0
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.4
1.3.3
1.3.2
1.3.1
1.3.0
1.2.2
1.2.1
1.2.0
1.1.2
1.1.1
1.1.0
1.0.1
1.0.0
0.8.28
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.10
0.8.9
0.8.8
0.8.7
0.8.6
0.8.5
0.8.1
0.8.0
0.7.2
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
0.5.1
0.5.0
0.4.2
0.4.1
0.4.0
0.3.7
0.3.5
0.3.0
0.2.0
0.1.0
BDD testing framework for Elixir inspired by RSpec.
Current section
Files
Jump to
Current section
Files
lib/espec/mock.ex
defmodule ESpec.Mock do
@moduledoc """
Defines 'expect` function to mock function using 'meck'.
:meck.new is called with options :non_strict and :passthrough.
The :non_strict allows create mocks for modules and functions that do not exist.
The :passthrough options allow call other functions in the module.
Information about mock is stored in the ':espec_mock_agent' set.
Mock are being unloaded after each example.
"""
@agent_name :espec_mock_agent
@default_options [:non_strict, :passthrough]
@doc """
Creates new mock using :meck. The default :meck options are [:non_strict, :passthrough]
but they can be overriden.
Stores mock in agent to remove it after spec.
"""
def expect(module, name, function, meck_options) do
opts = if Enum.empty?(meck_options), do: @default_options, else: meck_options
try do
:meck.new(module, opts)
rescue
error in [ErlangError] ->
case error do
%ErlangError{original: {:already_started, _pid}} -> :ok
_ -> raise error
end
end
:meck.expect(module, name, function)
agent_put({module, self()})
end
@doc "Unloads modules at the end of example"
def unload do
modules = agent_get(self()) |> Enum.map(fn {m, _p} -> m end)
:meck.unload(modules)
agent_del(self())
end
@doc "Starts Agent to save mocked modules."
def start_agent, do: Agent.start_link(fn -> MapSet.new() end, name: @agent_name)
@doc "Stops Agent"
def stop_agent, do: Agent.stop(@agent_name)
defp agent_get(pid) do
Agent.get(@agent_name, & &1)
|> Enum.filter(fn {_m, p} -> p == pid end)
end
defp agent_del(pid) do
new_set =
Agent.get(@agent_name, & &1)
|> Enum.reduce(MapSet.new(), fn {m, p}, acc ->
if p != pid, do: MapSet.put(acc, {m, p}), else: acc
end)
Agent.update(@agent_name, fn _state -> new_set end)
end
defp agent_put(key), do: Agent.update(@agent_name, &MapSet.put(&1, key))
end