对随机生成的值进行doctests

时间:2017-10-01 10:52:53

标签: unit-testing random elixir doctest

给出以下代码:

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

1 个答案:

答案 0 :(得分:2)

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的rand模块的内部结构发生变化。