How to Test Stdin with Rspec

Testing STDIN in Ruby

You can simply stub STDIN:

it "takes user's name and returns it" do
output = capture_standard_output { game.ask_for_name }
expect(output).to eq "What shall I call you today?"
allow(STDIN).to receive(:gets) { 'joe' }
expect(game.ask_for_name).to eq 'Joe'
end

Actually, you can do the same with STDOUT, without needing to change $stdout:

it "takes user's name and returns it" do
expect(STDOUT).to receive(:puts).with("What shall I call you today?")
allow(STDIN).to receive(:gets) { 'joe' }
expect(game.ask_for_name).to eq 'Joe'
end

how to test STDIN with RSpec

Because move_computer returns the input, I think you meant to say:

player.move_computer("O").should == "\n"

I would write the full spec like this:

describe Player do
describe "#move_computer" do
it "returns a line from stdin" do
subject.stub!(:gets) {"penguin banana limousine"}
STDOUT.should_receive(:puts).with("computer move")
subject.move_computer("O").should == "penguin banana limousine"
end
end
end

How to test stdin for a CLI using rspec

I ended up finding a solution that I think fairly closely mirrors the code for executing instructions from a file. I overcame the main hurdle by finally realizing that I could write cli.stub(:gets).and_return and pass it in the array of commands I wanted to execute (as parameters thanks to the splat * operator), and then pass it the "EXIT" command to finish. So simple, yet so elusive. Many thanks go to this StackOverflow question and answer for pushing me over the line.

Here is the code:

describe "executing instructions from the command line" do
let(:output) { capture(:stdout) { cli.execute } }

context "with valid commands" do
valid_test_data.each do |data|
let(:expected_output) { data[:output] }
let(:commands) { StringIO.new(data[:input]).map { |a| a.strip } }

it "should process the commands and output the results" do
cli.stub(:gets).and_return(*commands, "EXIT")
output.should include(expected_output)
end
end
end
# ...
end

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.

Testing ruby with rspec for file name and STDIN with while gets

How about this idea?

[EDITED]

For the main script…

require 'processor'
sources = ARGV.map{ |fname| File.open(fname) }
sources = [$stdin] if sources.empty?
Processor.new(sources).process

…and for processor.rb…

Class Processor
attr_reader :sources
attr_accessor :card_hash

def initialize(sources)
@sources = sources
@card_hash = Hash.new
end

def process
sources.each do |source|
source.each_line.do |line|
...

Then, for testing purposes, you can pass an array of one or more stub objects for the sources. The stub objects could be something like RSpec doubles or an instances of StringIO. See http://apidock.com/ruby/StringIO .

Testing gets in rspec (user input)

You can avoid this as such:

def run
puts "Enter 'class' to create a new class."
input = gets.chomp
end

describe 'gets' do
it 'belongs to Kernel' do
allow_any_instance_of(Kernel).to receive(:gets).and_return('class')
expect(run).to eq('class')
end
end

The method gets actually belongs to the Kernel module. (method(:gets).owner == Kernel). Since Kernel is included in Object and almost all ruby objects inherit from Object this will work.

Now if run is an instance method scoped in a Class I would recommend scoping the stubbing a bit more such that:

class Test
def run
puts "Enter 'class' to create a new class."
input = gets.chomp
end
end

describe 'gets' do
it 'can be stubbed lower than that' do
allow_any_instance_of(Test).to receive(:gets).and_return('class')
expect(Test.new.run).to eq('class')
end
# or even
it 'or even lower than that' do
cli = Test.new
allow(cli).to receive(:gets).and_return('class')
expect(cli.run).to eq('class')
end
end

Example

RSpec: Using a method stub to test interactive user input

You are receiving the error because you are passing the --format documentation as a parameter to RSpec.

gets reads the ARGV that have been passed. This also includes the RSpec parameters. You should use STDIN.gets so that you only read standard input and not the parameters.

You can read more about in this question:
https://stackoverflow.com/a/19799223/6156030

RSpec asking for user input

Your suggestions should work actually. But there is another option.

orig_stdin = $stdin 
$stdin = StringIO.new('exit')
assert(EchoApp.new.greeting,'Goodbye!')
# Or
expect(EchoApp.new.greeting).to eql('Goodbye!')
$stdin = orig_stdin

Let me know if this does not work.



Related Topics



Leave a reply



Submit