Creating a Plug.Conn dummy

Background

I have a controller that receives Plug requests via it’s process function. My objective is to test said function, without the need to perform a GET request.

Code

To achieve this I am calling the function directly. Following is the said function:

  @spec process(Conn.t, keyword) :: Conn.t
  def process(%Conn{} = conn, deps) do
    query_params =
      conn
      |> Conn.fetch_query_params()
      |> Map.get(:query_params)
      |> Map.delete("format")

    with  {:ok, results}  <- deps[:search].(query_params),
          {:ok, answer}   <- deps[:format].(results, "json")
    do
      Conn.send_resp(conn, Status.code(:ok), answer)
    else
      {:error, :json_encoding_failed, err} ->
        Conn.send_resp(conn, Status.code(:unprocessable_entity), "Failed to JSON enconde query results: #{inspect err}")
      {:error, :invalid_format, inv_format} ->
        Conn.send_resp(conn, Status.code(:bad_request), "Invalid format specified: #{inspect inv_format}")
    end
  end

My objective is to, by being able to call this function with injected dependencies, to simulate the errors json_encoding_failed and invalid_format.

Problem

The problem is that I still need to pass this function a Plug.Conn object. Now, this controller is really dummy, all it does is run 2 functions and handle the errors, so I don’t think I can abstract any logic from here)

So test this I need to pass in a dummy Plug.Conn object. But the code I am using doesn’t work:

conn = %Conn{}
Search.process(conn, deps)

It blows with the following error:

** (UndefinedFunctionError) function Plug.MissingAdapter.send_resp/4 is undefined (module Plug.MissingAdapter is not available)

Questions

  1. Is this the correct approach to testing my controller? I think I can’t extract more logic from there.
  2. Why am I getting this error? How can I create a dummy Plug.Conn object?

Maybe you don’t? I mean, I am sure there is solution for your problem but maybe better idea would be to move out the function from controller to a separate module, and make it not require conn but params extracted from it and assigns that you need.

Please do excuse for linking to my own article, but maybe “Technique #2in this article will be helpful for you?

2 Likes

There’s Plug.ConnTest as well as Phoenix.ConnTest with lot’s of helpers around testing things which require a conn struct.

Who said an empty conn struct is enough information to fulfill the functions you’re handing it to. Functions like Conn.send_resp do not work with just about any conn struct, but they require certain information to be present in it to do their job.

2 Likes

Read the article and fell in love with the idea of Workflows !
This is what I have envisioned for my controllers from the start, but due to my lack of knowledge was not able to do. You really do make it look really simple in your blog. Workflows. How comes I never thought of that?

I still have some questions, but overall, really loved Step 2. (I want to try Step1, but since I don’t use Phoenix, I only use Plug, I have some questions. Material for another post probably).

I didn’t know about those. Thanks for letting me know!

No one. This is just me trying to make something work and failing. Most of the time a dummy empty object works out, so I decided to try the same approach here.Turns out Plug has a lot more to it than I thought !

1 Like