0

I'm coding a game by taking a TDD first approach, and have gotten stuck because the test keeps stopping for user input (repo is here).

I want the test to simulate user input rather than prompting for it, as I've set up some let keywords and have tried to account for user input that comes in via gets.chomp.

Here is where the game prompts for user input:

game.rb

module ConnectFour
  class Game
    def start_game
      puts 'Welcome to Connect Four.'
      puts "Enter name of player 1 (red)"
      player1name = gets.chomp
      player1 = Player.new(player1name)
    end
  end
end 

And here is the test code:

game_spec.rb

require 'spec_helper'

module ConnectFour
  describe Game do
    let(:game) { Game.new }
    let(:player1name) { 'Bob' }
    let(:player1) { Player.new(player1name) }

    describe 'Instantiate game play objects' do

      describe 'Create player 1' do
        it 'Provide player 1 name' do
          allow_any_instance_of(Kernel)
          .to receive(:gets)
          .and_return(player1name)
        end
        it 'Instantiate player 1' do
          expect(player1.name).to eq player1name
        end
      end
    end # describe 'Instantiate game play objects'
  end # Describe 'Game'
end

So far I've tried encapsulating the gets.chomp in its own method as recommended here but this has no effect. I've also tried prefixing $stdin to gets.chomp statements in the Ruby code but yeah, that was pretty useless. I had asked a similar question here recently and thought I had understood how to simulate user input but obviously not... any help would be appreciated.

orlando21
  • 307
  • 1
  • 5
  • 15

1 Answers1

0

use allow_any_instance_of(Object) instead of Kernel. The module Kernel is included into Object. Kernel is not ever actually instantiated because it's a module.

kind of a small point, but it'd be more accurate if you stubbed gets to return a strinng ending in \n, otherwise you could remove the chomp from the tested functionn and the test will still pass

reproducable example

require 'rspec'
require 'rspec/expectations'

test_case = RSpec.describe "" do
  it "" do
    allow_any_instance_of(Object).to receive(:gets).and_return "something\n"
    puts gets.chomp
  end
end

test_case.run
max pleaner
  • 26,189
  • 9
  • 66
  • 118
  • Do you mean as shown in [this thread](https://stackoverflow.com/a/17258855/6180530). I've updated the code in `game.rb` and `game_spec.rb` (shown in repo) but the program still halts at gets. – orlando21 Apr 11 '18 at 17:03
  • I'm telling you to replace `allow_any_instance_of(Kernel)` (as shown in your question text) with `allow_any_instannce_of(Object)`. Of course there are other ways to achieve this and you can try and follow the advice in that other answer. I'm not covering that in mine though. Take it or leave it. – max pleaner Apr 11 '18 at 17:06
  • Hm. Tried that first but didn't work :-( Thanks anyway – orlando21 Apr 11 '18 at 17:08
  • I just tested this. It does work. Sorry to break it to you. – max pleaner Apr 11 '18 at 17:12
  • Alright, then I'm doing something wrong. This sounds elementary but just to confirm; you downloaded my repo, just changed that line you advised, and ran `bundle exec rspec`...and the code just ran straight thru without pause? If so, then I've probably been working too long on this problem and need to take a break. – orlando21 Apr 11 '18 at 17:17
  • @orlando21 i didn't download your code. I tried `allow_any_instance_of(Object).to receive(:gets).and_return "something\n"` in a minimal RSpec environment, and checked that `gets.chomp`returned `something`. – max pleaner Apr 11 '18 at 17:55
  • @orlando21 exited answer to include reproducible example – max pleaner Apr 11 '18 at 18:22