erlang 使用Mock或Mox模拟Elixir中的连续函数调用

nqwrtyyt  于 2022-12-16  发布在  Erlang
关注(0)|答案(1)|浏览(175)

我尝试模拟函数的多次调用,所以每次都返回不同的值。我不太熟悉 Elixir 和函数的概念。

defmodule Roller do
  def roll do
      1..10
      |>Enum.random()
  end
end

Roller每次调用都返回一个随机数。

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的思维方式可能与我的客观范式思维方式有点不同。测试VolunteerFinder模块的最正确Elixir的方式是什么?

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
2eafrhcq

2eafrhcq1#

我找到了一个可行的解决方案,但我不确定是否满意:

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

有没有更好的办法来解决这个问题?

相关问题