doctests для случайно сгенерированных значений

Учитывая следующий код:

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" генерируется случайным образом? Похоже, я следую как Enum.random проходит проверку


person category    schedule 01.10.2017    source источник


Ответы (1)


doctest Enum.random явно устанавливает начальное значение для теста, что делает результат будущих вызовов функций :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 не изменится, эти семена будут продолжать давать одни и те же значения, что достаточно для doctest (вы всегда можете исправить тесты, если они сломаются в будущих версиях Erlang).

Итак, чтобы исправить ваш doctest, вы должны выполнить этот код один раз в iex (вы можете изменить начальные значения, если хотите):

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

А затем жестко закодируйте возвращаемые значения в вашем doctest. Теперь ваши тесты должны проходить до тех пор, пока внутреннее устройство модуля rand Erlang не изменится.

person Dogbert    schedule 01.10.2017
comment
Спасибо - теперь у меня есть более четкое представление о том, как работает раздача. - person category; 01.10.2017