Background
I have some code that invokes a given function a certain number of times. I pass this function in the parameters so it is easy to stub.
However I need to know that under some conditions the function was called exactly X times. ExUnit.Case
has an extremely limited support for this however, so I went ahead with the “send yourself a given message trick”
Code
@tag :wip
test "calls given function X times" do
my_pid = self()
deps = [
lookup_fn: fn _key ->
send(my_pid, :lookup)
{:ok, 1}
end
]
MyApp.do_work(deps)
# how to test I got the :lookup message exactly twice?
end
Research
The first easy solution is using receive multiple times:
receive do
msg -> assert msg == :lookup
end
receive do
msg -> assert msg == :lookup
end
receive do
msg -> assert msg == :lookup
end
# etc...
For example, if I wanted to check :lookup
was called 10 times, I would have 10 receives.
This solution is very poor for 2 reasons:
- A ton of code repetition
- It doesn’t check that
:lookup
was called exactly X times, it checks it was received at least X times.
I searched for some libraries but couldn’t find anything. The closes thing I found was the SO question using macros:
Which I tried to adapt into an assert_receive_at_least
(but failed miserably):
defmacro assert_receive_at_least(pattern, times, timeout \\ 500) do
quote do
defp loop(_pattern, current_times, total_times, _timeout) when current_times == total_times do
{:ok, :received}
end
defp loop(pattern, current_times, total_times, timeout) do
receive do
msg -> assert pattern == msg
after timeout -> {:error, :timeout}
end
end
defp run(pattern, times, timeout) do
loop(pattern, 0, times, timeout)
end
run(unquote(pattern), unquote(times), unquote(timeout))
end
end
Questions
- How do I check if a given message was received X times?
- How do I check if a given message was received at least X times?
- Are there any libraries that add decent stub support ?