I worked on a small CLI (Command Line Interface) in Ruby over the weekend and I wanted to test the user input on the command line and the output that the program will print out. I figured out this simple FakeIO class that helps me do that.

# 'support/fake_io'
class FakeIO

  attr_accessor :input, :output

  def initialize(input)
    @input = input
    @output = ""
  end

  def gets
    @input.shift.to_s
  end

  def puts(string)
    @output << "#{string}\n"
  end

  def write(string)
    @output << string
  end

  def self.each_input(input)
    io = new(input)
    $stdin = io
    $stdout = io

    yield

    io.output
  ensure
    $stdin = STDIN
    $stdout = STDOUT
  end
end

Here is a small spec to demonstrate how it can be used:

require 'support/fake_io'

class CLI
  def self.run
    loop do
      input = $stdin.gets
      break if input.empty?
      $stdout.puts input
    end
  end
end

describe "CLI" do
  it "can read and write to command line" do
    output = FakeIO.each_input(["line1", "line2", "line3"]) { CLI.run }
    output.should == "line1\nline2\nline3\n"
  end
end

FakeIO.each_input method accepts an array of input lines that will be entered on the command line and a block that calls the program. It returns back what will be printed out on the command line as output so we can write expectations on it. We inject the FakeIO instance on the fly as IO dependency and after the block we revert back to default IO.