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
Get Sidekiq to Execute a Job Immediately
How to Convert a Ruby Object to JSON
Which Ruby Version am I Really Running
Putting the Results of Pp (Or Anything Outputted to Console) into a String
Check If an Array Is Subset of Another Array in Ruby
Deleting a Modified Object from a Set in a No-Op
Converting a Hash into a Nested Hash
Error Installing Ruby with Rvm (Osx 10.8)
Rails Unable to Convert Unpermitted Parameters to Hash
Before/After Suite When Using Ruby Minitest
Handling Exceptions Raised in a Ruby Thread
HTML Code Inside Buttons with Simple_Form
Yaml Indentation for Array in Hash