I'm trying to mock function multiple calls, so it returns every time specific different value. I am not that familiar with Elixir and functional concepts.
defmodule Roller do
def roll do
1..10
|>Enum.random()
end
end
Roller returns a random number every call.
defmodule VolunteerFinder do
import Roller
def find(list) do
find(list, []);
end
defp find([] = _list, result) do
result
end
defp find([head | tail] = _list, result) do
result = [%{name: head, score: Roller.roll()} | result]
find(tail, result)
end
end
So assuming the list
contains more than one element, the roller is called 2 times. In my test, I need to control it somehow.
I tried it with Mock. I would like to do something like this in the simplest possible way. It would be great not to have to save some state anywhere or run separate processes for every call. I know Elixir thinking might be a little different than the objective paradigm mindset I have. What's the most correct Elixir way of testing the VolunteerFinder
module?
defmodule VolunteerFinderTest do
use ExUnit.Case
import Mock
import Roller
test_with_mock(
"Find volunteer for list with one element",
Roller,
[roll: fn() -> 5 end]
) do
assert VolunteerFinder.find(["John"]) == [%{name: "John", score: 5}]
end
test_with_mock(
"Find volunteer for list with two elements",
Roller,
[roll: fn
() -> 2
() -> 5
end]
) do
assert VolunteerFinder.find(["John", "Andrew"])
== [%{name: "Andrew", score: 5}, %{name: "John", score: 2}]
end
end
I found a working solution, but I am not sure if I'm satisfied with it:
test_with_mock(
"Find volunteer for list with two elements",
Roller,
[roll: fn () -> mock_roll end]
) do
send self(), {:mock_return, 1}
send self(), {:mock_return, 5}
assert VolunteerFinder.find(["Sergey", "Borys"])
== [%{name: "Borys", score: 5}, %{name: "Sergey", score: 1}]
end
def mock_roll do
receive do
{:mock_return, value} ->
value
after
0 ->
raise "No mocked returns received"
end
end
Is there any more elegant way of solving the problem?