WithClauseError,长生不老药单元测试匹配 (:ok, value}
WithClauseError, elixir unit tests match with (:ok, value}
我正在尝试在 elixir 中编写安全的功能代码,并使用单元测试来确认我的代码是否正常工作。这是控制器代码:
def calculate_price(start_time, end_time, zone, payment_type) do
with( {:ok} <- validate_times(start_time, end_time),
{:ok} <- validate_zone(zone),
{:ok} <- validate_payment_type(payment_type)
) do
elapsed_minutes = div(Time.diff(end_time, start_time), 60)
cond do
zone == "A" && elapsed_minutes <= 15 -> {:ok, 0}
zone == "B" && elapsed_minutes <= 90 -> {:ok, 0}
zone == "A" && elapsed_minutes > 15 && payment_type == "hourly" -> {:ok, calc(elapsed_minutes - 15, 2, 60)}
zone == "B" && elapsed_minutes > 90 && payment_type == "hourly" -> {:ok, calc(elapsed_minutes - 90, 1, 60)}
zone == "A" && elapsed_minutes > 15 && payment_type == "real" -> {:ok, calc(elapsed_minutes - 15, 0.16, 5)}
zone == "B" && elapsed_minutes > 90 && payment_type == "real" -> {:ok, calc(elapsed_minutes - 90, 0.08, 5)}
end
else
{:error, error} -> IO.puts error
end
end
defp validate_times(start_time, end_time) when end_time > start_time, do: :ok
defp validate_times(_start_time, _end_time), do: {:error, "The start/end time is wrong"}
defp validate_zone(zone) when zone == "A" or zone == "B", do: :ok
defp validate_zone(_zone), do: {:error, "The zone is wrong"}
defp validate_payment_type(payment_type) when payment_type == "hourly" or payment_type == "real", do: :ok
defp validate_payment_type(_payment_type), do: {:error, "The payment type is wrong"}
defp calc(minutes_to_pay, price_per_minutes, minutes_per_price_increment) do
cond do
rem(minutes_to_pay, minutes_per_price_increment) > 0 ->
(div(minutes_to_pay, minutes_per_price_increment) + 1) * price_per_minutes
true -> div(minutes_to_pay, minutes_per_price_increment) * price_per_minutes
end
end
controller_test代码:
test "calculate price; zone: B, paymentType: real" do
# 4 hours and 30 minute difference
startTime = ~T[12:00:00.000]
endTime = ~T[16:30:00.000]
zone = "B"
paymentType = "real"
assert {:ok, 2.88} == calculate_price(startTime, endTime, zone, paymentType)
end
对于此代码,我试图验证传入的参数是否正确,以便在我的代码的正确路径上 return 结果是 {:ok, value}
。如果参数错误我想知道为什么会发生错误。目前我只是打印到命令行,但最终我想 return {:error, reason}
。只是将 {:error, error}
放在 else 子句中会导致不同的错误。
测试用例的结果是:
** (WithClauseError) no with clause matching: :ok
我认为这意味着我的 calculate_price 函数是 returning {:ok}
。我不明白为什么 with
子句中的值被 returned 而不是 do
或 else
子句中的值!
我的 elixir 版本是 1.9.1.
首先检查您的代码是否可以手动运行。从错误消息来看,我认为您的代码在逻辑上的某处有错误,而不是 returns {:ok, ...}
。大概是Datetime
。你通常使用DateTime.compare()
来进行比较。
最快的检查方法是将结果与变量进行模式匹配并断言该变量。 Mix
将向您显示返回的结果以及您的预期结果。
result = calculate_price(startTime, endTime, zone, paymentType)
assert result == {:ok, 2.88}
问题在这里:
{:ok} <- validate_times(start_time, end_time)
方法 returns 裸 :ok
原子,当您尝试将其模式匹配到 with
中的单个元素元组 {:ok}
时,显然失败了。
那行得通:
with :ok <- validate_times(start_time, end_time),
:ok <- validate_zone(zone),
:ok <- validate_payment_type(payment_type) do
...
end
此外,使用 mix format
任务根据指南格式化您的代码,否则阅读起来非常困难。
这也适用于 with
中的后续条款。
旁注: 这就是我们如何使用模式匹配和守卫以更精巧的方式重写您的 cond
子句:
case {zone, elapsed_minutes, payment_type} do
{"A", elapsed_minutes, _} when elapsed_minutes <= 15 -> {:ok, 0}
{"B", elapsed_minutes, _} when elapsed_minutes <= 90 -> {:ok, 0}
{"A", _, "hourly"} -> {:ok, calc(elapsed_minutes - 15, 2, 60)}
{"B", _, "hourly"} -> {:ok, calc(elapsed_minutes - 90, 1, 60)}
{"A", _, "real"} -> {:ok, calc(elapsed_minutes - 15, 0.16, 5)}
{"B", _, "real"} -> {:ok, calc(elapsed_minutes - 90, 0.08, 5)}
end
我正在尝试在 elixir 中编写安全的功能代码,并使用单元测试来确认我的代码是否正常工作。这是控制器代码:
def calculate_price(start_time, end_time, zone, payment_type) do
with( {:ok} <- validate_times(start_time, end_time),
{:ok} <- validate_zone(zone),
{:ok} <- validate_payment_type(payment_type)
) do
elapsed_minutes = div(Time.diff(end_time, start_time), 60)
cond do
zone == "A" && elapsed_minutes <= 15 -> {:ok, 0}
zone == "B" && elapsed_minutes <= 90 -> {:ok, 0}
zone == "A" && elapsed_minutes > 15 && payment_type == "hourly" -> {:ok, calc(elapsed_minutes - 15, 2, 60)}
zone == "B" && elapsed_minutes > 90 && payment_type == "hourly" -> {:ok, calc(elapsed_minutes - 90, 1, 60)}
zone == "A" && elapsed_minutes > 15 && payment_type == "real" -> {:ok, calc(elapsed_minutes - 15, 0.16, 5)}
zone == "B" && elapsed_minutes > 90 && payment_type == "real" -> {:ok, calc(elapsed_minutes - 90, 0.08, 5)}
end
else
{:error, error} -> IO.puts error
end
end
defp validate_times(start_time, end_time) when end_time > start_time, do: :ok
defp validate_times(_start_time, _end_time), do: {:error, "The start/end time is wrong"}
defp validate_zone(zone) when zone == "A" or zone == "B", do: :ok
defp validate_zone(_zone), do: {:error, "The zone is wrong"}
defp validate_payment_type(payment_type) when payment_type == "hourly" or payment_type == "real", do: :ok
defp validate_payment_type(_payment_type), do: {:error, "The payment type is wrong"}
defp calc(minutes_to_pay, price_per_minutes, minutes_per_price_increment) do
cond do
rem(minutes_to_pay, minutes_per_price_increment) > 0 ->
(div(minutes_to_pay, minutes_per_price_increment) + 1) * price_per_minutes
true -> div(minutes_to_pay, minutes_per_price_increment) * price_per_minutes
end
end
controller_test代码:
test "calculate price; zone: B, paymentType: real" do
# 4 hours and 30 minute difference
startTime = ~T[12:00:00.000]
endTime = ~T[16:30:00.000]
zone = "B"
paymentType = "real"
assert {:ok, 2.88} == calculate_price(startTime, endTime, zone, paymentType)
end
对于此代码,我试图验证传入的参数是否正确,以便在我的代码的正确路径上 return 结果是 {:ok, value}
。如果参数错误我想知道为什么会发生错误。目前我只是打印到命令行,但最终我想 return {:error, reason}
。只是将 {:error, error}
放在 else 子句中会导致不同的错误。
测试用例的结果是:
** (WithClauseError) no with clause matching: :ok
我认为这意味着我的 calculate_price 函数是 returning {:ok}
。我不明白为什么 with
子句中的值被 returned 而不是 do
或 else
子句中的值!
我的 elixir 版本是 1.9.1.
首先检查您的代码是否可以手动运行。从错误消息来看,我认为您的代码在逻辑上的某处有错误,而不是 returns {:ok, ...}
。大概是Datetime
。你通常使用DateTime.compare()
来进行比较。
最快的检查方法是将结果与变量进行模式匹配并断言该变量。 Mix
将向您显示返回的结果以及您的预期结果。
result = calculate_price(startTime, endTime, zone, paymentType)
assert result == {:ok, 2.88}
问题在这里:
{:ok} <- validate_times(start_time, end_time)
方法 returns 裸 :ok
原子,当您尝试将其模式匹配到 with
中的单个元素元组 {:ok}
时,显然失败了。
那行得通:
with :ok <- validate_times(start_time, end_time),
:ok <- validate_zone(zone),
:ok <- validate_payment_type(payment_type) do
...
end
此外,使用 mix format
任务根据指南格式化您的代码,否则阅读起来非常困难。
这也适用于 with
中的后续条款。
旁注: 这就是我们如何使用模式匹配和守卫以更精巧的方式重写您的 cond
子句:
case {zone, elapsed_minutes, payment_type} do
{"A", elapsed_minutes, _} when elapsed_minutes <= 15 -> {:ok, 0}
{"B", elapsed_minutes, _} when elapsed_minutes <= 90 -> {:ok, 0}
{"A", _, "hourly"} -> {:ok, calc(elapsed_minutes - 15, 2, 60)}
{"B", _, "hourly"} -> {:ok, calc(elapsed_minutes - 90, 1, 60)}
{"A", _, "real"} -> {:ok, calc(elapsed_minutes - 15, 0.16, 5)}
{"B", _, "real"} -> {:ok, calc(elapsed_minutes - 90, 0.08, 5)}
end