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

sen
Hi All, I set a environment variables in dev.exs , like below code. when i start server, how can i set the ${enable} value? thanks. d...
New
myronmarston
The Elixir Typespec docs show the following syntax for keyword lists in typespecs: # ... | [key: type] # keyword lists...
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
earth10
Hi, I’m just starting to build a side-project with Elixir and Phoenix and doing some basic test with Elixir alone. What strikes me is th...
New
stefanchrobot
What’s the safe way to decode a JSON string into a struct? I want to avoid calling String.to_atom. Jason.decode can give me a map with st...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
script
If I have a string “1000 cfu/ml” . I want to remove the characters and / and space . So the string is like this "1000" What is the ...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
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

Other popular topics Top

sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 42920 311
New
AstonJ
Posting this to see if we can make things easier for people to get into Neovim. If you use Neovim and have a favourite distro please let ...
New
greenz1
I have a phoenix application from which a user can download multiple(5-6) files of size 1MB. I couldn’t find anything related to sending ...
New
Patoshizzle
After calling mix ecto.create I get this error: 17:00:32.162 [error] GenServer #PID<0.412.0> terminating ** (Postgrex.Error) FATAL...
New
JeremM34
Hello, how can I check the Phoenix version ? Thanks !
New
chrismccord
Phoenix 1.4.0 released Phoenix 1.4 is out! This release ships with exciting new features, most notably with HTTP2 support, improved deve...
688 30877 112
New
msaraiva
Surface is an experimental library built on top of Phoenix LiveView and its new LiveComponent API that aims to provide a more declarative...
564 43622 214
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
klo
Got a question about when to concat vs. prepending items to list then reversing to achieve appending. So i know lists boil down to [1 | ...
New

We're in Beta

About us Mission Statement