How to Use Rspec to Mock Stdin/Stdout to Test Console Reads & Writes

Can I use RSpec to mock stdin/stdout to test console reads & writes?

You can use mocks and have the method called more than once by listing multiple values in the and_return() method. These will be returned, one on each call, in the order given.

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

STDIN.should_receive(:read).and_return("value1", "value2", "value3")

You can do similar things with STDOUT:

STDOUT.should_receive(:puts).with("string")

See the RSpec mocking documentation for more information.

How can I test rspec user input and output with Highline?

The best way to find out how to test Highline is to see how the author tests his package.

class TestHighLine < Test::Unit::TestCase
def setup
@input = StringIO.new
@output = StringIO.new
@terminal = HighLine.new(@input, @output)..
end
..
def test_agree
@input << "y\nyes\nYES\nHell no!\nNo\n"
@input.rewind

assert_equal(true, @terminal.agree("Yes or no? "))
assert_equal(true, @terminal.agree("Yes or no? "))
assert_equal(true, @terminal.agree("Yes or no? "))
assert_equal(false, @terminal.agree("Yes or no? "))
....
@input.truncate(@input.rewind)
@input << "yellow"
@input.rewind

assert_equal(true, @terminal.agree("Yes or no? ", :getc))
end


def test_ask
name = "James Edward Gray II"
@input << name << "\n"
@input.rewind

assert_equal(name, @terminal.ask("What is your name? "))
....
assert_raise(EOFError) { @terminal.ask("Any input left? ") }
end

Etc., as shown in his code. You can find this information in the highline source paying close attention to the setup, which I have highlighted in the link.

Notice how he uses the STDIN IO pipe to act in the place of typing the keys on the keyboard.

What this indicates, really, is that you don't need to use highline to test that kind of thing. The setup in his tests are really key here. Along with his use of StringIO as an object.

Issue with Rspec Test for a Ruby Script that takes user input for Hash elements

Use

STDIN.gets.chomp

See this answer.

The best way to test this is to mock IO#gets with an object and method that returns a canned response. An RSpec mock would look something like:

STDIN.should_receive(:gets).and_return("A Book Title")

See this answer for a couple more examples. Set these up in the appropriate before :each blocks and they will intercept the call to gets in your test.

which version of RSpec does the expectation should_receive belong to?

should_recieve is in the RSpec book in the chapter on Mocks (page 183 and onwards).

Is there more you can't find?

sandbox testing environments exist for TDD'ing command line application

Depends on what you're trying to do, but I test most of my command line Ruby by mocking out the file system and STDIN/STDOUT. Using dependency injection I often end up with something along these lines:

describe Add do
it 'writes the result to standard out' do
console = mock('STDOUT')
console.should_receive(:puts).with('5')

Add.new(console).execute(3,2)
end
end

class Add
def initialize(out = STDOUT)
@out = out
end

def execute(command_line_args)
@out.puts(command_line_args.inject(:+))
end
end

Add.new.execute(ARGS)

By using default values I can inject in the test, but leave it out of the production code.

Hope that helps!

Brandon

Rspec: No such file or directory @ rb_sysopen -

You can try to use a little different approach:

describe "gets.rb" do
it "should output 'Hello, name!'" do
allow_any_instance_of(Object).to receive(:gets).and_return("lena")

expect { require_relative "../gets.rb" }.to output("Hello, Lena!\n").to_stdout
end
end

allow_any_instance_of I took from https://makandracards.com/makandra/41096-stubbing-terminal-user-input-in-rspec

Reading user input in console applications is usually done using Kernel#gets.

The page suggests to use Object.any_instance.stub(gets: 'user input') but it's deprecated syntax already and I've updated it.



Related Topics



Leave a reply



Submit