Parameterized testing and setup block

Given this simplified application code:

defmodule Bla do
  def hello(name), do: "Hello #{name}"
end

And this test code:

defmodule BlaTest do
  use ExUnit.Case

  defp user(_), do: {:ok, name: "User"}
  defp admin(_), do: {:ok, name: "Admin"}

  describe "#hello/1" do
    for role <- [:user, :admin] do
      setup role

      test "greets the #{role}", %{name: name} do
        IO.inspect({unquote(role), name})
        assert Bla.hello(name) == "Hello #{name}"
      end
    end
  end
end

The tests pass but the IO.inspect output is:

{:user, "Admin"}
{:admin, "Admin"}

I was expecting:

{:user, "User"}
{:admin, "Admin"}

Why is setup role always returning ‘Admin’?

All setups in a single describe block are run before each test:

ExUnit.start()

defmodule Test do
  use ExUnit.Case

  def foo(_), do: IO.puts("foo") && %{}
  def bar(_), do: IO.puts("bar") && %{}
  def baz(_), do: IO.puts("baz") && %{}

  describe "Hello" do
    setup :foo

    test "1" do
      assert IO.puts("test 1")
    end

    setup :bar

    test "2" do
      assert IO.puts("test 2")
    end
  end

  describe "World" do
    setup :baz

    test "3" do
      assert IO.puts("test 3")
    end
  end
end

output:

baz
test 3
.foo
bar
test 2
.foo
bar
test 1
1 Like

Adding to what @martosaur said…

Try swapping your for comprehension and the describe lines.

Also, starting with Elixir 1.18, ExUnit now has builtin parameterized test support

1 Like

Thank you both for your answers. Swapping the for and describe lines did the trick.