Cody Bontecou

Mocking HTTP Responses in Elixir and Phoenix

August 13, 2023 · 2 minute read · elixir,testing,mocking

I just came across this error while attempting to mock the response of a 3rd party api:

** (UndefinedFunctionError) function LeagueInfoMocks.get_live/0 is undefined (module LeagueInfoMocks is not available)

The Problem

I couldn't wrap my head around it. I have this simple mock module defined:

defmodule LeagueInfoMocks do
  def get_live do
    %{...}
  end
end

And a test module to interact with the get_live function:

defmodule LeagueInfoTest do
  use ExUnit.Case
  test "format_info" do
    data = LeagueInfoMocks.get_live()

    [match | _tail] = data

    assert LeagueInfo.format_info(data) == %{...}
  end
end

But running mix test would consistently give me the ** (UndefinedFunctionError) function LeagueInfoMocks.get_live/0 is undefined (module LeagueInfoMocks is not available).

The Solution

Most articles and threads mentioned moving the LeagueInfoMocks module in the test/support/* directory, so I did. This didn't change the error message.

I eventually found this Stackoverflow comment that mentioned some configuration needed in the mix.exs file.

Supposedly, mix phx.new adds the test/support/* support when a Phoenix project is created. In my case, I'm building off of a simple Elixir application. This required me to configure my mix.exs file to look like so:

defmodule LolesportsConsumer.MixProject do
  use Mix.Project

  def project do
    [
      app: :lolesports_consumer,
      version: "0.1.0",
      elixir: "~> 1.15",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      elixirc_paths: elixirc_paths(Mix.env())
    ]
  end

  # Run "mix help compile.app" to learn about applications.
  def application do
    [
      extra_applications: [:logger]
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:httpoison, "~> 2.1"},
      {:jason, "~> 1.4"}
    ]
  end

  defp elixirc_paths(:test), do: ["lib", "test/support"]
  defp elixirc_paths(_), do: ["lib"]
end

The key differences were:

  1. Adding elixirc_paths: elixirc_paths(Mix.env()) to project
  2. Adding these two lines to the file:
    • defp elixirc_paths(:test), do: ["lib", "test/support"]
    • defp elixirc_paths(_), do: ["lib"]

Conclusion

With these configuration changes, I am able to properly call LeagueInfoMocks.get_live() and write tests against an expected HTTP response.

Newsletter

Subscribe to get my latest content. No spam.