Jonathan Tuzman
Jonathan Tuzman

Reputation: 13262

Testing gets in rspec (user input)

My class has this #run method that so far is just this, to test the testing:

def run
    puts "Enter 'class' to create a new class."
    input = $stdin.gets.chomp
    binding.pry

And in the tests so far I've got

  allow($stdin).to receive(:gets).and_return 'class'
  cli.run

Doing it this way I am able to see, in the pry session, that input has been set to 'class', as intended.

Is there a way to do with without adding $stdin to my call to gets in my method itself? i.e., input = gets.chomp

I've tried allow(cli.run).to receive(:gets).and_return 'class' But then in the pry session, input is equal to the first line of the spec file!

Upvotes: 0

Views: 1266

Answers (1)

engineersmnky
engineersmnky

Reputation: 29328

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

Upvotes: 2

Related Questions