1

I have an ExUnit test that pings an endpoint. That endpoint calls a function that makes an external call via an http client that is determined by the environment a la Jose Valim's famous post.

In the test environment, I'm using a mock module of HTTPoison.

defmodule HTTPoisonMock do
  def get(_url), do: raise "You need to define this function for your test"
end

In the test itself, I'm trying to redefine this module so that the function returns a canned response.

test "/my_endpoint" do
  defmodule HTTPoisonMock do
    def get(_url) do
      {:ok, %HTTPoison.Response{body: []}}
    end
  end

  conn = conn(:get, "/my_endpoint")
  ...

  assert conn.status == 200
end

However, the redefined module is not used. I get the original error raised when I run the test.

** (ArgumentError) You need to define this function for your test

I've tried to do this with the mock library as well, which raises a different error, even if I'm mocking HTTPoison directly.

require HTTPoison

test "/my_endpoint" do
  with_mock HTTPoison, [:get, fn(_url) -> {:ok, %HTTPoison.Response{body: []}} end] do
    conn = conn(:get, "/my_endpoint")

    ...

    assert conn.status == 200
  end
end

** (UndefinedFunctionError) function HTTPoison.start/0 is undefined (module HTTPoison is not available)

Why isn't my redefined module being used?

steel
  • 11,883
  • 7
  • 72
  • 109
  • You can't redefine a module like this as far as I know. Can you post the code you used with `mock` (and the error message if it's not exactly identical to this)? – Dogbert Feb 10 '17 at 17:16
  • @Dogbert I've updated the code with the `mock` version. Error is different. – steel Feb 10 '17 at 17:26
  • Could you try also mocking `:start/0`? Something like `with_mock HTTPoison, [get: fn(_url) -> {:ok, %HTTPoison.Response{body: []}} end, start: fn() -> end] do`. – Dogbert Feb 10 '17 at 17:31
  • @Dogbert that worked, thank you. That error message is misleading, then. Why did it say `module HTTPoison is not available`? – steel Feb 10 '17 at 17:39
  • Oh. I didn't even read that part which is why I suggested adding `start/0`! – Dogbert Feb 10 '17 at 17:41

1 Answers1

4

It seems the problem is already resolved, but I would answer the original question for future visitors.

To redefine the module in the test, one might:

test "/my_endpoint" do
  Code.eval_string """
    defmodule HTTPoisonMock do
      def get(_url) do
        {:ok, %HTTPoison.Response{body: []}}
      end
    end
  """

  # do stuff

  after
    purge HTTPoisonMock
  end
end

This is heavily used in Elixir core tests, grep the repo for purge.

Aleksei Matiushkin
  • 119,336
  • 10
  • 100
  • 160