steel
steel

Reputation: 12520

Elixir: Redefine module in test

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?

Upvotes: 1

Views: 1077

Answers (1)

Aleksei Matiushkin
Aleksei Matiushkin

Reputation: 120990

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.

Upvotes: 4

Related Questions