I have this code in a test, which doesn’t quite work:
defmodule TurtleTest do
use ExUnit.Case, async: true
defmodule WorldSpy do
Turtles.World.__info__(:functions)
|> Enum.map(fn {name, arity} ->
params =
Stream.unfold(0, fn n -> {:"param_#{n}", n + 1} end)
|> Enum.take(arity) # I need to get this…
def unquote(name)( ) do # to be the list of params here
IO.puts unquote(to_string name) <> " called"
end
end)
end
# ...
end
See the comments above, but is there a way for me to dynamically build up the parameter list like this?
I would like to build a module that is a test double spy for another module. It would support the same function calls with the same arities. All those functions would do is log calls to them. Afterward, I could make assertions about those calls.
I welcome any critique of my approach.
I have read José’s mocking article and I believe it supports this usage, which seems more mock as a noun than verb to me.
Regardless of the merit of my intentions though, it would be interesting to also learn the answer to my asked question, if possible.
defmodule Turtles.World do
def foo(a, b), do: a + b
def bar(a), do: a
def baz(a, b, c), do: a + b + c
end
defmodule WorldSpy do
Turtles.World.__info__(:functions)
|> Enum.map(fn {name, arity} ->
params =
for _ <- 1..arity, do: {:_, [], nil}
def unquote(name)(unquote_splicing(params)) do # to be the list of params here
IO.puts unquote(to_string name) <> " called"
end
end)
end
WorldSpy.__info__(:functions) |> IO.inspect # [bar: 1, baz: 3, foo: 2]
WorldSpy.foo(1, 2)
WorldSpy.bar(1)
WorldSpy.baz(1, 2, 3)