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

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

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