Module Plug individual unit test?

How do I test module Plugs individually?

All the examples of “Plug test” I see make actual requests with paths all the way from Endpoint to actions. So it tests the whole thing and changing other things would affect the test without changing the module itself.

I’d like to make contained tests only for Plugs. I’d need conn after Endpoint but before Router. It might look like

test "plugs App.MyPlug", %{conn: conn} do
  conn = conn
    |> plug(App.Endpoint)
    |> plug(App.MyPlug)

  assert conn == some_desired_state
end

Can I actually do this with setup?

Also, is this approach something not feasible or unnecessary? I thought this is closer to normal function tests.

I don’t personally test plugs, just test that they have their desired effect as a side-effect of other areas they affect.

If you want to test in isolation though (which is perfectly reasonable) there is no need to do it as a “ConnCase”—that is actually testing way too much. You should be able to manually up a %Plug.Conn{} with the fields you care about, pass it in, then assert the resulting conn has your expected changes.

3 Likes

Sounds about right.

Plugs wanted inputs from some of the predecessors.

I ended up with a mini endpoint and a flimsy helper with a creative name.

setup tags do
  Feder.Core.Data.Case.sandbox(tags)
 
  Phoenix.ConnTest.build_conn()
  |> plug(Plug.Session, Feder.Endpoint.session())
  |> plug(Plug.Parsers, Feder.Endpoint.parsers())
  |> Plug.Conn.fetch_session()
  |> then(&{:ok, conn: &1})
end

def plug(conn, module, opts \\ []), do: conn |> module.call(module.init(opts))

Just a heads-up that there’s a Plug function called Plug.run/3 exacly for running multiple plugs, I love it!

Plug.run(conn, [{Plug.Head, []}, &Plug.Conn.fetch_session/1])
5 Likes

I was looking for this :sob:

1 Like