2014-05-21 104 views
2

我正在使用RSpec来测试我的摇滚纸剪刀游戏。包括在我begin_game功能我有以下代码:Rspec用户输入while循环测试

user_input = gets.chomp.downcase.to_sym 
while !choices.include? user_input 
    puts "Please choose a valid selection : rock, paper, or scissors" 
    user_input = gets.chomp.downcase.to_sym 
end 

我想测试不同的可能user_inputs。我试过这个:

let(:new_game) {RockPaperScissors.new} 
....... 
context 'validate that the user input is one of the given choices' do 
    it 'should prompt the user for a new input if the original one is invalid' do 
    new_game.stub(:gets) {"r"} 
    expect(new_game.begin_game).to eq("Please choose a valid selection : rock, paper, or scissors") 
    end 
end 

但是这会导致无限循环的“Please choose valid selection ...”被输出到终端。我阅读了RSpec模拟文档,但我很难理解。

+2

,我认为你应该做'STDIN.stub(:获得)'或'Kernel.stub(:获得)',而不是'new_game.stub' – bjhaid

回答

2

它循环的原因是因为new_game.stub(:gets) { "r" }将永远返回r无论多少次你称它。因此user_input将永远不会包含有效的输入,并且您的测试将永远运行。

要解决这个问题,您应该在new_game#gets经过一定次数的尝试后返回有效的选择。

例如,

new_game.stub(:gets) do 
    @counter ||= 0 
    response = if @counter > 3 # an arbitrary threshold 
       "rock" 
      else 
       "r" 
      end 
    @counter += 1 
    response 
end 

这将导致您的测试打印Please choose a valid selection... 4次,然后终止。

根据你如何实施RockPaperScissors#begin_game,你写的测试仍然不会通过。这是因为puts("a string")将始终返回nil。此外,while循环也将返回nil。所以上面的代码片段不会返回字符串"Please choose a valid selection : rock, paper, or scissors"

,将合格begin_game实现是:

def begin_game 
    user_input = gets.chomp.downcase.to_sym 
    if choices.include? user_input 
    # return something here 
    else 
    "Please choose a valid selection : rock, paper, or scissors" 
    end 
end 

,但在这一点上,我可能会重命名为handle_move,并将它接受参数作为参数,以避免在首位磕碰gets

def handle_move(input) 
    if choices.include? input 
    "Great move!" 
    else 
    "Please choose a valid selection : rock, paper, or scissors" 
    end 
end 
+2

我只是用这种思想的变化来测试相关情况。这真的很有帮助。谢谢! – Taylor714