如何在使用ExUnit进行测试时伪造IO输入? [英] How do I fake IO input when testing with ExUnit?
问题描述
我有一个Elixir程序,我想测试哪个用户通过 IO.gets
多次输入。我会如何着手在测试中伪造这个输入?注意:我想为每个 IO.gets
执行此操作的首选方法是将您的代码分为纯(无副作用)和不纯(io)。所以如果你的代码如下所示:
IO.gets
...
...
...
IO.gets
...
...
尝试将IO.gets之间的部分提取到可独立于 IO.gets
测试的函数中:
def fun_to_test do
input1 = IO.gets
fun1(input1)
input2 = IO.gets
fun2 input2)
end
然后你可以单独测试这些函数。如果, case
或中,这并不总是最好的做法, code> cond
语句。
另一种方法是将 IO
作为显式依赖:
def fun_to_test(io \\\ IO)do
io.gets
...
...
...
io.gets
...
...
结束
通过这种方式,您可以从生产代码中使用它,而无需进行任何修改,但在测试中,您可以将它传递给一些不同的模块 fun_to_test(FakeIO)
。如果提示不同,您可以在 gets
参数上进行模式匹配。
defmodule FakeIO do
def gets(prompt1),do:value1
def gets(prompt2),do:value2
end
如果它们始终相同,则需要保持获取$的次数c $ c>被调用:
defmodule FakeIO do
def start_link do
Agent.start_link(fn - > 1 end,name:__MODULE__)
end
$ b def get(_prompt)do
times_called = Agent.get_and_update(__ MODULE__,fn state - >
{state,state + 1}
end)
case times_called do
1 - > value1
2 - > value2
end
end
end
最后一个实现是一个完全有效的内部状态模拟。在测试中使用它之前,您需要调用 FakeIO.start_link
。如果这是你在许多地方需要做的事情,你可能会考虑一些嘲讽的图书馆,但正如你所看到的 - 这不是太复杂。要使 FakeIO
更好,您可以打印提示。我在这里跳过了这个细节。
I have an Elixir program I'd like to test which gets input from the user via IO.gets
several times. How would I go about faking this input in a test?
Note: I would like to return a different value for each IO.gets
The preferred way to do it is to split your code into pure (no side effects) and impure (does the io). So if your code looks like this:
IO.gets
...
...
...
IO.gets
...
...
try to extract the parts between IO.gets into functions that you can test in isolation from IO.gets
:
def fun_to_test do
input1 = IO.gets
fun1(input1)
input2 = IO.gets
fun2(input2)
end
and then you can test the functions in isolation. This isn't always the best thing to do, especially if the impure parts are deep inside if
, case
or cond
statements.
The alternative is to pass the IO
as an explicit dependency:
def fun_to_test(io \\ IO) do
io.gets
...
...
...
io.gets
...
...
end
This way you can use it from you production code without any modification, but in your test you can pass it some different module fun_to_test(FakeIO)
. If the prompts are different you can just pattern match on the gets
argument.
defmodule FakeIO do
def gets("prompt1"), do: "value1"
def gets("prompt2"), do: "value2"
end
If they are always the same you need to keep the state of how many times the gets
was called:
defmodule FakeIO do
def start_link do
Agent.start_link(fn -> 1 end, name: __MODULE__)
end
def gets(_prompt) do
times_called = Agent.get_and_update(__MODULE__, fn state ->
{state, state + 1}
end)
case times_called do
1 -> "value1"
2 -> "value2"
end
end
end
This last implementation is a fully working mock with its internal state. You need to call FakeIO.start_link
before using it in the test. If this is what you need to do in many places you may consider some mocking library, but as you can see - this isn't too complicated. To make the FakeIO
even better you can print the prompt. I skipped this detail here.
这篇关于如何在使用ExUnit进行测试时伪造IO输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!