简体   繁体   中英

Elixir doctest fails for function that returns random values

I have a function in Elixir that produces three random RGB tuples in a list.

defmodule Color do



  @doc """
  Create three random r,g,b colors as a list of three tuples

  ## Examples

      iex> colors = Color.pick_color()
      iex> colors
      [{207, 127, 117}, {219, 121, 237}, {109, 101, 206}]

  """
      def pick_color() do
        color = Enum.map((0..2), fn(x)->
          r = Enum.random(0..255)
          g = Enum.random(0..255)
          b = Enum.random(0..255)
          {r, g, b}
        end)
end

When I run my tests, my doctests fail. The resulting list of tuples are different than what is defined in my doctest. How can I write a doctest for a function that returns a random value?

You can make the random functions deterministic by setting the seed of :rand 's random number generator. This is also how Enum.random/1 is tested in Elixir.

First, open iex and set the seed of the current process to any value:

iex> :rand.seed(:exsplus, {101, 102, 103})

Then, run your function in iex

iex> Color.pick_color()

Now just copy this value into your doctest along with the :rand.seed call. By explicitly setting the seed, you're going to get the same values from the functions in :rand module and Enum.random/1 uses :rand internally.

iex(1)> :rand.seed(:exsplus, {1, 2, 3})
iex(2)> for _ <- 1..10, do: Enum.random(1..10)
[4, 3, 8, 1, 6, 8, 1, 6, 7, 7]
iex(3)> :rand.seed(:exsplus, {1, 2, 3})
iex(4)> for _ <- 1..10, do: Enum.random(1..10)
[4, 3, 8, 1, 6, 8, 1, 6, 7, 7]
iex(5)> :rand.seed(:exsplus, {1, 2, 3})
iex(6)> for _ <- 1..10, do: Enum.random(1..10)
[4, 3, 8, 1, 6, 8, 1, 6, 7, 7]

In order to test a function with doctests, you must be able to predict the output of your function . In this case, you can't predict the output of your function.


However you could test your function with regular tests.

Here is a test that would make sure Color.pick_color() produces a list of 3 tuples, using pattern matching:

test "pick color" do
  [{_, _, _}, {_, _, _}, {_, _, _}] = Color.pick_color()
end

You could also check if each value is between 0 and 255 , etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM