Bhushan Lodha
Bhushan Lodha

Reputation: 6862

Write test for accepting input from command line

I am fairly new to rspec and want to write test in rspec for getting input from command line in Ruby. How do I go about it? Also, explain the test. Thanks

Upvotes: 0

Views: 1387

Answers (2)

Simon Perepelitsa
Simon Perepelitsa

Reputation: 20639

The general approach is to make such kind of objects swappable. In your case, gets is implicitly called on $stdin. So you can make an optional argument called "input" that defaults to $stdin and call gets on it.

Here is an simple example of Calculator that takes some input and gives the result back.

class Calculator
  def initialize input = $stdin
    @input = input
  end

  def process
    eval @input.gets
  end
end

Now you can run puts Calculator.new.process, type 1 + 2 and you will see 3.

You won't need any special tools for testing this because you can easily pass an IO object and write to it right in your tests. IO.pipe is a good option for this:

describe "Calculator" do
  before do
    reader, @writer = IO.pipe
    @calc = Calculator.new(reader)
  end

  it "can sum up two numbers" do
    @writer.puts "1 + 2"
    result = @calc.process
    result.should eq(3)
  end
end

You can also use StringIO instead which is not a real IO and does not require a UNIX-like environment. Although you will need to rewind the stream each time you write.

require "stringio"

describe "Calculator" do
  before do
    @input = StringIO.new
    @calc = Calculator.new(@input)
  end

  it "can sum up two numbers" do
    @input.puts "1 + 2"
    @input.rewind
    result = @calc.process
    result.should eq(3)
  end
end

The upside of this approach versus stubbing are less brittle tests and a better design. The tests are less brittle because if you decide to change the implementation and use getc instead of gets (read characters one by one) for example you won't need to change the tests. And the design is better because now you can easily give commands from a different source such as a file Calculator.new(File.open("calculated_list.txt")). Or a fake IO which you can use in your tests!

Upvotes: 2

megas
megas

Reputation: 21791

By using mocks:

STDIN.should_receive(:read).and_return("your string")

Also I like the approach which is described here. I think that the last one is more suitable for your case.

Upvotes: 2

Related Questions