1

我正在尝试模拟函数多次调用,因此它每次都会返回特定的不同值。我对 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 的思维方式可能与我的客观范式思维方式略有不同。测试模块的最正确的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
4

1 回答 1

1

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

  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

有没有更优雅的方法来解决问题?

于 2021-12-29T16:02:22.603 回答