Elixir中返回随机值的函数doctest失败,如何编写正确用例?
这是个很常见的问题——doctest默认会严格匹配输出的字面量,但随机函数每次返回的结果都不一样,自然会失败。下面给你几种实用的解决方案,你可以根据需求选择:
方案1:验证返回值的结构与合法性(推荐)
对于随机生成的内容,我们不需要验证具体数值,而是要确保它符合预期的结构和取值范围。你可以在doctest里分步骤验证:
defmodule MyRGBModule do @doc """ Generates a list containing 3 random RGB tuples. ## Examples iex> rgb_list = MyRGBModule.generate_rgb_list() # 验证列表长度是3 iex> length(rgb_list) 3 # 验证每个元素都是合法的RGB元组(分量在0-255之间) iex> Enum.all?(rgb_list, fn {r, g, b} -> ...> is_integer(r) and r in 0..255 and ...> is_integer(g) and g in 0..255 and ...> is_integer(b) and b in 0..255 ...> end) true """ def generate_rgb_list do for _ <- 1..3, do: {Enum.random(0..255), Enum.random(0..255), Enum.random(0..255)} end end
这种方法的优势是完全不依赖随机种子,不管在什么环境下运行,只要函数逻辑正确,doctest就能通过。它聚焦于函数的行为正确性,而不是具体的随机输出,这也是随机函数测试的核心目标。
方案2:固定随机种子,匹配具体输出
如果你需要验证函数生成的随机值符合预期的逻辑(比如确认随机数生成的范围确实正确),可以在doctest中临时固定随机种子,这样每次运行doctest时都会得到相同的“随机”结果:
defmodule MyRGBModule do @doc """ Generates a list containing 3 random RGB tuples. ## Examples # 固定随机种子,确保每次doctest得到相同结果 iex> :rand.seed(:exsplus, {1234, 5678, 9012}) iex> MyRGBModule.generate_rgb_list() [{186, 213, 14}, {227, 15, 197}, {106, 208, 121}] """ def generate_rgb_list do for _ <- 1..3, do: {Enum.random(0..255), Enum.random(0..255), Enum.random(0..255)} end end
⚠️ 注意:不同Elixir版本的随机数生成器实现可能有差异,所以这个方法可能存在版本兼容性问题。另外,如果你在函数中使用的是:crypto模块的随机函数(比如:crypto.rand_uniform/2),需要对应设置:crypto的种子(不过:crypto的种子通常不建议手动设置,因为它依赖系统熵)。
方案3:在doctest中直接使用断言
你也可以在doctest里直接调用ExUnit的assert宏,验证每个返回值的合法性:
defmodule MyRGBModule do @doc """ Generates a list containing 3 random RGB tuples. ## Examples iex> MyRGBModule.generate_rgb_list() |> Enum.each(fn {r, g, b} -> ...> assert r in 0..255, "Red component out of range: \#{r}" ...> assert g in 0..255, "Green component out of range: \#{g}" ...> assert b in 0..255, "Blue component out of range: \#{b}" ...> end) :ok """ def generate_rgb_list do for _ <- 1..3, do: {Enum.random(0..255), Enum.random(0..255), Enum.random(0..255)} end end
这种方式和方案1类似,但更简洁,而且可以自定义错误提示,方便调试。
总结一下:优先选择方案1或3,它们更健壮、通用;只有当你需要验证具体的随机逻辑时,再考虑方案2。
内容的提问来源于stack exchange,提问作者Alex Fallenstedt
相关产品推荐
相关产品推荐

