elixir - 测试一个长生不老药功能
问题描述
我有一个Product
模式,它有一个UPI(unique product identifier)
例如。A985748BNG6784C
. 这是一个自动生成的唯一产品标识符。
我有一个函数upi_generate()
调用另一个外部函数gen_nano_id()
来生成这个随机的唯一 ID。
如果偶然生成的 idgen_nano_id()
已经生成,则函数upi_generate()
递归调用自身,直到时间gen_nano_id()
生成唯一的 id。从而生成独特的UPI
.
gen_nano_id()
有时会返回重复的 ID,为此我使用递归调用编写了以下代码。
def gen_nano_id() do //external function
Nanoid.generate(10, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")
end
# TODO: write test case for this
def upi_generate() do // required function
upi = "A" <> gen_nano_id() <> "C"
case get_product_with_upi(upi) do
nil ->
upi
_ ->
upi_generate()
end
end
// Check if product with UPI already exists
defp get_product_with_upi(upi) do
from(p in "snitch_products", select: p.upi, where: p.upi == ^upi)
|> Repo.one()
end
现在,我必须测试重复 id 的 id 重新生成逻辑。
我的测试方法涉及以下逻辑。创建一个有重复的两个产品,UPI
并尝试达到_
案例比较的部分。
为此,我模拟了(我不控制此函数的行为)gen_nano_id()
.
现在,我面临的问题是模拟导致创建始终相同的 id 无论如何,我进入无限循环。
我无法找到一种方法来exit condition(nil)
使用gen_nano_id
.
解决方案
José Valim Mocks和明确的合同有很好的写作。它说
始终将“mock”视为名词,而不是动词
这意味着您不应该模拟生成功能。你最好创建一个生成器并模拟它。
有点像这样:
defmodule Generator do
@callback gen_id :: integer()
end
defmodule NanoGenerator do
@moduledoc "Used in dev/prod"
@behaviour Generator
@impl true
def gen_id() do
get_nano_id() # external function or whatever
end
end
defmodule TestGenerator do
@moduledoc "Used in test"
@behaviour Generator
use Agent # to store state
@ids ~w|foo foo bar|
@impl true
def gen_id() do
id = # get the counter from Agent, and increase it
@ids[id]
end
end
现在你已经准备好从生成器返回你想要的任何东西了。
推荐阅读
- matlab - 使用函数句柄时,MATLAB cellfun 向量化速度很慢
- c++ - 将用户价值与枚举中的价值进行比较
- machine-learning - 如何为 2D 输入和输出创建深度学习模型?
- python - xarray.Dataset.weighted(...) 的问题
- javafx - 如何从主控制器类将动作侦听器设置为对话框确定按钮
- ggplot2 - 为什么在 RStudio 中清除我的全局环境可以解决我的 ggplot 缺失轴问题?
- python - /admin/accounts/picture/ 处的 OperationalError 没有这样的表:accounts_picture
- c++ - 为什么 boost::asio::ip::tcp::basic_stream_socket::available 运行时间长?
- javascript - 随机生日的概率
- html - 减小页面宽度时防止导航项换行