Testing user input from the CLI?

From the documentation, I can use capture_io/2 to capture user input from the CLI. However, the code in the documentation only works once: if the user is expected to give input only one single time.

What if the user is expected to give more than one input?
The following test


  import ExUnit.CaptureIO

  describe "capture_io" do
    test "captures IO" do
      assert capture_io([input: "this is input", capture_prompt: false], fn ->
               input = IO.gets("> ")
               IO.puts(input)

               input = IO.gets("> ")
               IO.puts(input)
             end) == "this is input\nthis is input"
    end
  end

fails with:

     test/guessing_game_test.exs:7
     Assertion with == failed
     code:  assert capture_io([input: "this is input", capture_prompt: false], fn ->
              input = IO.gets("> ")
              IO.puts(input)
              input = IO.gets("> ")
              IO.puts(input)
            end) == "this is input\nthis is input\n"
     left:  "this is input\neof\n"
     right: "this is input\nthis is input\n"
     stacktrace:
       test/guessing_game_test.exs:8: (test)

Basically, I have a function, that is an infinite loop, and I want to test the outcome of this function based on certain sequence of user inputs. Anyone know how to do that? :thinking:

I cannot give a list of inputs to be passed to IO either:

capture_io([input: ["this is input", "this is input"], capture_prompt: false], fn ->
  some_function_that_gets_user_input()
end) == "this is input\nthis is input\n"

As the :input option of capture_io/2 need to be a string :thinking:

I’d probably go the route of using a custom IO device and explicitly passing it to the function as an parameter. That way you’ve full control over it.

2 Likes