Fl4m3Ph03n1x

Fl4m3Ph03n1x

Mox test failing with `stub_with`

Background

I have a small app with a pool manager, a couple workers and a registry.
For the sake of learning Mox, I made a small test that uses Mox, but it fails for a reason I can’t understand.

Code

This code is a MWE app that starts a registry and a pool:

defmodule MoxIssue.Application do
  use Application

  def start(_type, _args) do
    Supervisor.start_link(
      [
        MoxIssue.ExRegistry,
        MoxIssue.Pool
      ],
      strategy: :one_for_one
    )
  end
end

The pool creates 3 workers and acts as a supervisor:

defmodule MoxIssue.Pool do

  alias MoxIssue.Worker

  require Logger

  @registry Application.fetch_env!(:mox_issue, :registry)

  def start_link do
    children = Enum.map(1..3, &worker_spec/1)

    Logger.debug("Starting supervisor")

    res = Supervisor.start_link(
      children,
      strategy: :one_for_one,
      name: @registry.via_tuple({__MODULE__, __MODULE__})
    )

    Logger.debug("Supervisor started")
    res
  end

  defp worker_spec(worker_id), do:
    Supervisor.child_spec({Worker, {worker_id}}, id: {worker_id})

  def child_spec(_) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start_link, []},
      type: :supervisor
    }
  end

end

Each Worker is a dummy echo worker that saves a list of messages echoed:

defmodule MoxIssue.Worker do
  use GenServer

  require Logger

  @registry Application.fetch_env!(:mox_issue, :registry)

  defmodule State do
    defstruct messages: [], worker_id: nil
  end

  def start_link({worker_id}) do
    Logger.debug("Starting worker #{inspect worker_id}")

    res = GenServer.start_link(
      __MODULE__,
      %State{worker_id: worker_id},
      name: @registry.via_tuple({__MODULE__, worker_id})
    )

    Logger.debug("Worker registers OK")
    res
  end

  def echo(msg, id) do
    [{pid, _val}] = @registry.lookup({__MODULE__, id})
    GenServer.call(pid, {:echo, msg})
  end

  def init(state), do: {:ok, state}

  def handle_call({:echo, msg}, _from, state) do
    Logger.info(msg)
    new_state = %State{state | messages: [msg] ++ state.messages}
    {:reply, :ok, new_state}
  end
end

Nothing extraordinary here. The most complex piece of code is the Registry, which I took from Elixir in Action and slightly modified for this example. Because Mox really wants you to have contracts, here is the contract used and it’s implementation:

defmodule MoxIssue.ProcessRegistry do
  @type via_tuple_type  ::
    {:via, module, {module, {module, any}}} |
    {:via, module, {module, {module, any}, any}}
  @type module_key :: {module, any}

  @callback lookup(module_key)                  :: [{pid, any}]
  @callback via_tuple(module_key)               :: via_tuple_type
  @callback via_tuple(module_key, any)          :: via_tuple_type
end
defmodule MoxIssue.ExRegistry do
  @behaviour MoxIssue.ProcessRegistry

  alias MoxIssue.ProcessRegistry

  ########
  # API  #
  ########

  @impl ProcessRegistry
  def lookup({_module, _id} = key), do: Registry.lookup(__MODULE__, key)

  @impl ProcessRegistry
  def via_tuple({_module, _id} = key), do:
    {:via, Registry, {__MODULE__, key}}

  @impl ProcessRegistry
  def via_tuple({_module, _id} = key, value), do:
    {:via, Registry, {__MODULE__, key, value}}

  @spec start_link() :: {:ok, pid} | {:error, any}
  def start_link, do:
    Registry.start_link(keys: :unique, name: __MODULE__)

  #############
  # Callbacks #
  #############

  @spec child_spec(any) :: Supervisor.child_spec
  def child_spec(_) do
    Supervisor.child_spec(
      Registry,
      id: __MODULE__,
      start: {__MODULE__, :start_link, []}
    )
  end
end

Test

The test is rather useless. I am trying to replicate an issue with another app we have, so this is the smallest working example I could come up with:

defmodule MoxIssueTest do
  use ExUnit.Case

  import Mox

  alias MoxIssue.RegistryMock
  alias MoxIssue.ExRegistry
  alias MoxIssue.Worker

  # Make sure mocks are verified when the test exits
  setup :verify_on_exit!

  describe "create/1" do

    test "returns an application ready to use with default values" do

      stub_with(RegistryMock, ExRegistry)

      {:ok, _pid} = Worker.start_link({1})
    end

  end
end

This test fails with:

no expectation defined for MoxIssue.RegistryMock.via_tuple/1 in process #PID<0.163.0>

Which I don’t understand. The whole reason for using stub_with is exactly because I don’t want to expect anything, nor do i want to assert that function X was called Y times. I just want to replace the Mock with an implementation and have it run.

Why am I getting this error?

Most Liked

woohaaha

woohaaha

What was the solution for this?

Where Next?

Popular in Questions Top

stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 record...
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
mgjohns61585
Could someone help me? I'm making my first elixir program, number guessing game. I can't figure out how to convert the user's guess from ...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
chewm
Hi guys, nice to meet you to the whole forum, I’m new here, I’m trying to configure visual studio code for elixir, right now the intellis...
New
sabri
Can someone explain the settings of pool_size of Ecto in config file? and what is the recommend size? Thanks
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
273 38985 115
New
freewebwithme
Using vs code and installed ElixirLS: support and debugger. And I got an error popped up on start up says Failed to run ‘elixir’ comma...
New
William
I would like to know that is there any online source for learning Phoenix Framework for building E-Commerce Store? Any advantage on build...
New
lessless
I believe there are people here who are dealing with CSV files import on the daily basis, and since Excel is a really popular tool there ...
New
New
quazar
How to set Jason to encode all fields in ecto schema, I don’t care about security and implementing only is taking long list of attributes...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
vac
Hi, I'm quite new in Elixir and I'm trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New

We're in Beta

About us Mission Statement