Testing with mocks in processes

Hello I am fairly new to Elixir and am running into an issue testing an external API call from a GenServer process. I have this Messenger module which I’d like to send an email using an external library, OtherEmailer. I would like to test that the OtherEmailer receives a message with expected data. Here is an example of the module under test:

defmodule Messenger do
  use GenServer

  def start_link do
    GenServer.start_link(__MODULE__, :ok, [name: __MODULE__])
  end

  def send_message data do
    GenServer.cast(__MODULE__, {:send_message, data})
  end

  def handle_cast({:send_message,  data}, state) do
    send_email data
    {:noreply, state}
  end

  defp send_email data do
    OtherEmailer.send(message: data)
  end
end

And this is the test I am using. The test will fail. However, if I were to test send_email directly it will pass. I am wondering what setup I am missing to connect the processes in my test case?

defmodule MessengerTest do
  use ExUnit.Case
  import Mock

  test "sends an email" do
    with_mock OtherEmailer, [], [send: fn(message: _data) -> :ok end] do
      data = %{body: "data"}

      Messenger.send_message(data)

      assert called OtherEmailer.send(message: data)
    end
  end
end

You’ll find many of us avoid the whole with_mock thing for reasons eloquently articulated in: http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/

1 Like

I made a package called stub_alias which kinda does exactly what is suggested in that article in a more concise package. It’s worked pretty well for me in this respect.