如何在使用ExUnit进行测试时伪造IO输入? [英] How do I fake IO input when testing with ExUnit?

查看:102
本文介绍了如何在使用ExUnit进行测试时伪造IO输入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Elixir程序,我想测试哪个用户通过 IO.gets 多次输入。我会如何着手在测试中伪造这个输入?注意:我想为每个 IO.gets

$ b $返回一个不同的值b

解决方案

执行此操作的首选方法是将您的代码分为纯(无副作用)和不纯(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

如果它们始终相同,则需要保持获取被调用:

  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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆