0

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!

WilliamG
  • 127
  • 2
  • 8
  • Have you tried global mode for Mox? https://hexdocs.pm/mox/Mox.html#module-global-mode Another thing to try would be to refactor your GenServer so you can pass the API module as an argument -- that way you can ensure that each instance is using the module you specify (e.g. the mock or the real). – Everett May 09 '22 at 11:15
  • Yes, I have tried both global mode and have tried to pass the module as an argument but I still get the same behaviour. I have ensured that the mocked module is being used but it always seem to use the real implementation – WilliamG May 10 '22 at 09:38
  • Maybe try removing the use of `stub_with` to use a total mock. The `setup :set_mox_from_context` also might be causing some confusion. That might help identify where things are going off the rails. – Everett May 10 '22 at 11:03
  • have you tried to share the expectation defined in the test with the gen_server process? i.e using an explicit allow? expectation |> allow(test_pid, gen_server_pid) – Oladipo Olasemo Jun 15 '22 at 22:53

0 Answers0