随机生成值的文档测试

doctests for randomly generated values

给定以下代码:

defmodule Pullapi.Workout do                                                                                     
  import Pullapi.Numbers

  @moduledoc """                                                                                                 
  Functions that generate a workout representation                                                               
  """

  @doc """                                                                                                       
  Returns a pullup set defined by the number of `max_reps` a user can do, a `percentage`, and the                
  number of maximum additional or decremented reps, `rep_bound`.                                                 

  ## Examples                                                                                                    
  iex> Pullapi.Workout.pullup_set(20, 60, 5)                                                                     
  %{"Action" => "Pullups", "Units" => "14"}                                                                      
  """
  @spec pullup_set(integer, integer, integer) :: map()
  def pullup_set(max_reps, percentage, rep_bound) do
    median = max_reps * (percentage / 100)
    unit_range = Pullapi.Numbers.median_range(round(median), rep_bound)
    units = Enum.random(unit_range)

    %{"Action" => "Pullups", "Units" => "#{units}"}
  end
end

doctest 失败:

  1) test doc at Pullapi.Workout.pullup_set/3 (1) (PullapiTest)
     test/pullapi_test.exs:4
     Doctest failed
     code: Pullapi.Workout.pullup_set(20, 60, 5) === %{"Action" => "Pullups", "Units" => "14"}
     left: %{"Action" => "Pullups", "Units" => "8"}
     stacktrace:
       lib/pullapi/workout.ex:13: Pullapi.Workout (module)

有没有办法指定"Units"值是随机生成的?我好像在关注 the way Enum.random is doctested

Enum.random 的 doctest 明确设置了测试的种子值,这使得将来调用 :rand 函数的结果具有确定性。

iex(1)> for _ <- 1..10 do
...(1)>   :rand.seed(:exsplus, {101, 102, 103})
...(1)>   Enum.random([1, 2, 3])
...(1)> end
[2, 2, 2, 2, 2, 2, 2, 2, 2, 2]

编写测试的人最有可能 运行 函数一次检查设置这些种子值后返回的值,然后将它们放入 doctest。除非 :rand 的内部工作方式发生变化,否则这些种子将继续产生相同的值,这对于 doctests 来说已经足够了(如果它在未来的 Erlang 版本中出现问题,您可以随时修复测试)。

所以,要修复你的 doctest,你应该在 iex 中执行一次这段代码(你可以根据需要更改种子值):

:rand.seed(:exsplus, {101, 102, 103})
Pullapi.Workout.pullup_set(20, 60, 5)

然后在您的 doctest 中对返回值进行硬编码。您的测试现在应该会通过,直到 Erlang 的 运行d 模块的内部结构发生变化。