Moussenger

Moussenger

Pass variables created in a defmacro definition to the do: block

Hi!

I’m trying to avoid redundant testing (that means, tests that are made in the same way all the time but with slightly different parameters). For example, I have this all the time when I want to test that the call to a controller was ok:

setup do
  count = 3
end

test "responds with right schema", %{conn: conn, swagger_schema: schema} do
    conn
    |> create_authenticated_conn()
    |> get(~p"/something",  %{a: 1})
    |> validate_resp_schema(schema, "Schema")
    |> json_response(200)
    |> assert_length(count)
end

The things that change are the method call (get, post…), the params, the schema to evaluate, and, optionally if I want to make more assertions (as checking the length of the result array).

So, I thought of creating a macro that simplifies all this work, parameterizing the values that need to be parameterized and also allowing a do: block element to add additional checks. I end up with this:

defmacro test_ok(schema_name, method, url, params \\ nil, do: block) do
  quote do
    test "responds with right schema", %{conn: conn, swagger_schema: schema} do
      response =
        conn
        |> create_authenticated_conn()
        |> unquote(method)(unquote(url), unquote(params))
        |> validate_resp_schema(schema, unquote(schema_name))
        |> json_response(200)

      evaluate_response(response, block)
    end

    defp evaluate_response(var!(response), block) do
      unquote(block)
    end
  end
end

If I ignore the response part and the block part (evaluate_response method) all works fine. As soon as I want to add to the macro the block part and pass the response to inside the body, I have two problems. First, let’s put an example of code:

test_ok("Schema", :get, ~p"/something") do
  assert_length(response, count)
end

Then, the first problem is about the response not being recognized inside the block code. And the other is count not being available neither, although in the way normal test macro, is recognized perfectly.

What is my mistake here?

Most Liked

ziinc

ziinc

You can use a for..do loop in an exunit test. I highly recommend not over-complicating your tests with a macro unless you absolutely need to.

See this for an example

To answer your question, your block is a compile time ast and can’t be used like an arg at runtime.

Also, you’d be redefining a new private function with the same arity for each macro, so it would not work for more than 1 test.

Where Next?

Popular in Questions Top

vegabook
I’m brand new to Phoenix and I have stripped one of the demo applications to the bone. I just want to get an svg up on the screen. Here i...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
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
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
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
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

Other popular topics Top

baxterw3b
Hi guys, i’m new in the Elixir world, and i have to say, that i love it! i’m having some problem to understand anonymous functions with ...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
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
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 49084 226
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 42533 114
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement