使用 Mock 或 Mox 模拟 Elixir 中的连续函数调用
Mocking consecutive function calls in Elixir with Mock or Mox
我正在尝试模拟函数多次调用,所以它 returns 每次都有特定的不同值。我不太熟悉 Elixir 和功能概念。
defmodule Roller do
def roll do
1..10
|>Enum.random()
end
end
滚轮returns每次调用一个随机数。
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
所以假设list
包含不止一个元素,滚子被调用了2次。在我的测试中,我需要以某种方式控制它。
我用 Mock 试过了。我想以最简单的方式做这样的事情。如果不必在任何地方保存一些状态或 运行 为每个调用单独处理,那就太好了。我知道 Elixir 的想法可能与我的 objective 范式思维模式略有不同。 Elixir 测试 VolunteerFinder
模块的最正确 方法是什么?
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
我找到了一个可行的解决方案,但我不确定自己是否满意:
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
有没有更优雅的解法?
我正在尝试模拟函数多次调用,所以它 returns 每次都有特定的不同值。我不太熟悉 Elixir 和功能概念。
defmodule Roller do
def roll do
1..10
|>Enum.random()
end
end
滚轮returns每次调用一个随机数。
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
所以假设list
包含不止一个元素,滚子被调用了2次。在我的测试中,我需要以某种方式控制它。
我用 Mock 试过了。我想以最简单的方式做这样的事情。如果不必在任何地方保存一些状态或 运行 为每个调用单独处理,那就太好了。我知道 Elixir 的想法可能与我的 objective 范式思维模式略有不同。 Elixir 测试 VolunteerFinder
模块的最正确 方法是什么?
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
我找到了一个可行的解决方案,但我不确定自己是否满意:
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
有没有更优雅的解法?