Fl4m3Ph03n1x

Fl4m3Ph03n1x

How to test a Phoenix Controller with Hammox?

Background

I am trying to create a mock for one of my behaviours. To this end I am using Hammox (a variation of Mox which extends the api).

I have set my application so it gets which module to use from the configuration files, in this case config/test.exs:

config/test.exs

config :my_app, storage: StorageMock

And this is the test file:

test/my_app/application_test.exs

defmodule MyApp.ApplicationTest do
  @moduledoc false

  use ExUnit.Case, async: false
  use MyApp.ConnCase

  import Hammox

  test "client can handle an error response", %{conn: conn} do
    Hammox.defmock(StorageMock, for: MyApp.Storage)

    expect(StorageMock, :get, fn args ->
      assert args == "Chicago"

      # here we decide what the mock returns
      {:ok, %{body: "Some html with weather data"}}
    end)

    get(conn, "~p/api/users/validate")
  end
end

I am trying to test the controller’s endpoint,and I am basically mixing the docs of Hammox (GitHub - msz/hammox: 🏝 automated contract testing via type checking for Elixir functions and mocks · GitHub) with what i can grasp from a Testing controllers guide (Testing Controllers — Phoenix v1.8.8).

Problem

Unfortunately, I think my setup is incorrect, as I get this error:

Compiling 1 file (.ex)
** (Mix) Could not start application my_app: exited in: MyApp.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) The module StorageMock was given as a child to a supervisor but it does not exist
            (elixir 1.16.0) lib/supervisor.ex:797: Supervisor.init_child/1
            (elixir 1.16.0) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
            (elixir 1.16.0) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
            (elixir 1.16.0) lib/supervisor.ex:783: Supervisor.init/2
            (elixir 1.16.0) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 9.2) application_master.erl:293: :application_master.start_it_old/4

What am I missing here?
I assume there is some configuration somewhere to tell the VM that StorageMock is something from the library, but I can’t find it.

Marked As Solved

Fl4m3Ph03n1x

Fl4m3Ph03n1x

This is really close to the problem. Turns out my issue was that I was referencing StorageMock at application startup, namely:

defmodule MyApp.Application do
  @moduledoc false

  use Application

  @impl true
  def start(_type, _args) do
   children = 
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      {StorageMock, []},
      MyAppWeb.Endpoint
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

By removing StorageMock from the list of children (when running tests) the error was fixed.

For those of you curious, you can check in which env the application is running, by using Mix.env(). Thus, you can do something like:

  def start(_type, _args) do
    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children(Mix.env(), opts)
  end

  defp children(:test) do
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      MyAppWeb.Endpoint
    ]
  end

  defp children(_other_envs) do
    [
      MyAppWeb.Telemetry,
      {Phoenix.PubSub, name: MyApp.PubSub},
      {RealStorage, ["localhost:5221"]},
      MyAppWeb.Endpoint
    ]
  end

This is the solution I ended up going with, as it means you can make use of the config/test.exs to define what modules you want to use. You can even change modules at runtime by using Application.put_env/3 if you are inclined to do that, which can also come in handy when doing some specific types of tests.

Thanks for the help!

Also Liked

LostKobrakai

LostKobrakai

test_helper.exs is also loaded after application startup. What works is putting the defmock in a compiled file (not a script), e.g. in test/support/mocks.ex or something like that. See the documentation here: Mox — Mox v1.1.0

Where Next?

Popular in Questions Top

chokchit
** (DBConnection.ConnectionError) connection not available and request was dropped from queue after 2733ms. You can configure how long re...
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
New
beno
I will often find my self writing things similar to: case some_value do nil -> something() "" -> something() _ -> somethi...
New
tduccuong
Hi, is there any work on GUI with Elixir, that is similar to Electron/Javascript? My idea is to bundle Phoenix and BEAM into a single se...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
itssasanka
Hi all, Trying to get some more clarity over utc_datetime and naive_datetime for Ecto: The documentation above suggests that while ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
Nvim
Anybody knows a comprehensive comparison of Django and Phoenix, thanks for the help. Where are they similar? Where do they differ the m...
New
shahryarjb
Hello, I have map which I want to convert it to string like this: the map: %{last_name: "tavakkoli", name: "shahryar"} the string I ne...
New
jay1
Why is it that the mnesia database isn’t the most preferred database for use in Elixir/Phoenix?
New
joeerl
Hello again - after a longish gap I’ve decided I really must dig into Elixir and see what’s been happening here - so I have a few questio...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

We're in Beta

About us Mission Statement