Elixir mox - mocking service used by genserver

425 views Asked by At

I'm using Mox to mock a service Pokemon.Api (mock is called Pokemon.ApiMock) and everythings works fine. I have also created a custome ExUnit.CaseTemplate(Pokemon.Case) and am stubbing the mock implementation with the real implementation. So if I havent defined a mox.expect the test till relay on the real implementation (Pokemon.Api). This also works fine.

However here is when the problem comes ...

I also have a DynamicSupervisor which initiated a Genserver, and that genserver will use Pokemon.Api (or Pokemon.ApiMock in some testcases). In the testcases where I have defined a mox.expect the test works as usual. However if I haven't defined an expect, and should relay and the stub(real impentation) the test crashes. (And remember this doesn't happen if I try to access the implementation throgh the service.

Exception

** (Mox.VerificationError) error while verifying mocks for #PID<0.223.0>:

   * expected Pokemon.ApiMock.get_by_id/1 to be invoked once but it was invoked 0 times
 stacktrace:
   (mox 1.0.1) lib/mox.ex:713: Mox.verify_mock_or_all!/3
   (ex_unit 1.13.0) lib/ex_unit/on_exit_handler.ex:143: ExUnit.OnExitHandler.exec_callback/1
   (ex_unit 1.13.0) lib/ex_unit/on_exit_handler.ex:129: ExUnit.OnExitHandler.on_exit_runner_loop/0

Genserver

defmodule Pokemon.Server do

  ....

  @impl true
  def handle_info(:get, state) do
    # bit weird, but only for demonstration purposes :)
    _ = api_imp().get_by_id(1)
    {:noreply, state}
  end

  def api_imp() do
    Application.get_env(:pokemon, :api)
  end
end

Case

defmodule Pokemon.Case do
  use ExUnit.CaseTemplate

  setup _ do
    Mox.stub_with(Pokemon.ApiMock, Pokemon.Api)

    :ok
  end
end

test_helper

Mox.defmock(Pokemon.ApiMock, for: Pokemon.ApiBehavoir)
Application.put_env(:pokemon, :api, Pokemon.ApiMock)

ExUnit.start()

tests Test 1 works but test 2 crashes...

defmodule PokemonTest do
  use Pokemon.Case

  import Mox
  setup :set_mox_from_context
  setup :verify_on_exit!

  test "1" do
    Pokemon.Supervisor.get(1)
    .....
  end

  test "2" do
    expect(Pokemon.ApiMock, :get_by_id, fn _ -> {:ok, "fake"} end)
    Pokemon.Supervisor.get(1)
    ....
  end
end

Not really sure how I should proceed and would appriciate any help I can get If I have been unclear at any point please tell

Thanks!

0

There are 0 answers