TestCase to setup logged user

Im looking for a way to improve my controller tests. Currently I am doing something like this

test "lists all menu_items", %{conn: conn, user: user} do
  conn = Plug.Test.init_test_session(conn, user_id: user.id)
  conn = get(conn, Routes.menu_item_path(conn, :index))
  assert html_response(conn, 200) =~ "some html"

To setup the user record I tried using this aproach (Using setup_all with database?) but I ran into some database errors when running all tests.

I could use setup instead of setup_all but that makes the test suite very slow.

Another aproach I tried was implementing mocks as José describe here

defmodule MyApp.LoggedUserCase do
  use ExUnit.CaseTemplate
  require Ecto.Query
  setup do
    user = Application.get_env(:my_app, :session_plug_account_module).get_user!(123)
    {:ok, user: user}

But some coworkers found it awkward to call Application.get_env(:my_app, :session_plug_account_module) on the authentication plug because it sounds like you are changing code just for the sake of the tests, I dont have a problem with it but others have.

The first attempt was to put some condition on the router to ignore the auth plug but it looks ugly/wrong as hell

pipeline :authenticated do
  if Mix.env() != :test do
    plug MyApp.Plugs.RequireSessionStatus, :authenticated

This is strange. Are you using bcrypt or similar to hash the user’s password? If so, are you configuring it properly for test environments so that it returns quickly?


The Programming Phoenix book suggests looking for a current_user assign within the same plug that pulls users out of the session.

def call(conn, _opts) do
  user_id = get_session(conn, @session_name)

  cond do
    conn.assigns[:current_user] -> conn
    user = user_id && People.get_user(user_id) -> assign_user(conn, user)
    true -> assign_user(conn, nil)

In your tests, simply assign current_user to the conn and you’re good to go.

It notes that this is controversial given that it is for testability. I don’t find it particularly controversial. My CurrentUser plug just happens to pass through a current_user if its already been set, which seems like a pretty reasonable default. And that just happens to make testing easier. :slight_smile:

1 Like

Yeah I agree.

That was it!
Thank you :smiley: