Elixir is a pretty new language and as such is still developing patterns and adapting existing patterns to its sometimes idiosyncratic ways. One of these concerns mocking.

José Valim and Lasse Ebert both rally against mocking libraries that basically fiddle around with the global mapping of module names to code, and I think that that is a very good thing. However, their solution leaves to be deserved for several reasons. A minor reason is that with Lasse’s solution, you will not be able to see in your test code that a mock is used. It is stowed away in configuration and the test helper script. I like languages that have everything out in the open, and this smells for me.

The bigger question, however, is what are you mocking? I’m from the OO world, and I like to mock objects - individual instances of classes in the OO world. In an OO language, you have an interface and two implementations (the mock one and the real one). Only in the individual test case you make the decision which one you need and instantiate the chosen one. For a unit test, you will want to mock implementation, but for an integration test the real one might just suit you well.

With the mock module plus config setup, you can’t do that. There’s effectively a singleton and the decision is made for all tests. I’d like to do better - have real mock objects and make it clear in the tests what we’re using.

So what is the equivalent of an object in Elixir? “That which encapsulates state and behavior”, which means a specific process and its associated code (callbacks, etcetera). Most simply, an object in Elixir is usually a Module (for the behavior) and a pid (for the state). If you use that as your object pointer, you can mock as you want. Here’s an example, say we have a persistence subsytem (and we only look at writing here to keep it simple):

defmodule Persistence do
  defmodule Behaviour do
    @callback persist(pid :: pid, key :: String.t, data :: Map.t) :: :ok
  end
end

So far, nothing special. Now, the API to persistence is going to look almost the same, but it takes a module as well as a pid to find out where to send to:

  ...

  def persist(_persister = {module, pid}, key, data) do
    :ok = Kernel.apply(module, :persist, [pid, key, data])
  end

So if we call Perstence.persist(...) then this function will basically forward the call to the module. An example is the mock, which I often implement right in the module as mock behavior is often simple and shared so we might as well offer up a default one. Here’s a possible mock implementation:

defmodule Mock do
  @behaviour Persistence.Behaviour

  def start_link do
    {:ok, pid} = Agent.start_link(fn -> %{} end)
    {:ok, {__MODULE__, pid}}
  end

  def persist(pid, key, data) do
    Agent.update(pid, fn cur -> Map.put(cur, key, data) end)
  end

  def get({_module, pid}) do
    Agent.get(pid, fn state -> state end)
  end
end

Two things of note here - we don’t return the standard {:ok, pid} tuple, but rather we combine module and pid and return that. There’s also a get function that we can use in tests to see whether data got persisted. Talking about tests, let’s see how this is used in a tests:

defmodule SomeTest
  use ExUnit.Case, async: true # shouldn't that be the default in Elixir anyway?

  test "My Beautiful test of Some" do
    {:ok, persister} = Persister.Mock.start_link()
    {:ok, my_thing_under_test} = Some.start_link(persister)
    ... do some stuff with my_thing_under_test ...
    persisted_stuff = Persister.Mock.get(persister)
    ... assert that things are in persisted_stuff
  end
end

I think that that’s reasonably decent code. It clearly shows we’re mocking Persister, it injects the mock into Some (whatever that may be), and when we done with our call, we simply ask the mock for its status and assert on that. In the production code it’s as simple as calling the API’s method:

defmodule Some

  ...

  def handle_call(:dump_your_state, _from, state) do
    Persister.persist(state.persister, state.key, state.data)
  end
end

assuming that persister, key and data are, of course, corresponding fields in Some’s state structure. Note that the fact that persister is not your usual pid, but it is completely transparent for the code that gets it injected, as is should be.

Conclusion

While module-based switching may work well, and has the advantage of no compile time overhead, I think it is too coarse and too opaque. The alternative presented here isn’t much harder to implement, comes with minimal run-time overhead, and has the advantage that test code becomes easier to follow and more flexible, as implementation-switching can be done on a case-by-case basis.