I've looked at other examples of tests, but most other examples don't necessarily have a variable that is equal to 'gets.chomp.downcase' and it's making it difficult for me to test.
The rest is for a chess game but I'm trying to make it so if you type in "new" in the introduction, it'll call the method #instructions, which displays the instructions and asks if you're ready to play.
Here's the method #introduction
def introduction
puts " \n"
print " Welcome to chess! "
puts "What would you like to do?"
puts "
* Start a new Game -> Enter 'new'
* Load a saved Game -> Enter 'load'
* Exit -> Enter 'exit'"
input = gets.chomp.downcase
if input == "new"
instructions
elsif input == "load"
load_game
elsif input == "exit"
exit!
else
introduction
end
end
Here's the test that I have for it that keeps displaying the error "Failure/Error: input = gets.chomp.downcase"
"NoMethodError: undefined method `chomp' for nil:NilClass"
describe Game do
describe "#introduction" do
it "starts a new game with input 'new'" do
io = StringIO.new
io.puts "new"
$stdin = io
game = Game.new
game.introduction
allow(game).to receive(:gets).and_return(io.gets)
expect(game).to receive(:instructions)
end
end
end
You have multiple problems with your approach. I won't enumerate them all, but instead focus on three key mistakes:
There are certainly other problems with your code and your tests, but that's where I'd start once you remove your reliance on #gets from within your test cases. For example, to test the various paths in your method, you should probably configure a series of tests for each expected value , where #and_return explicitly returns new
, load
, or whatever.
More pragmatically, you're most likely struggling because you wrote the code first, and now are trying to retrofit tests. While you could probably monkey-patch things to make it testable post-facto, you're probably better off refactoring your code to allow direct injection within your tests. For example:
def show_prompt
print prompt =<<~"EOF"
Welcome to chess! What would you like to do?
* Start a new Game -> Enter "new"
* Load a saved Game -> Enter "load"
* Exit -> Enter "exit"
Selection:\s
EOF
end
def introduction input=nil
show_prompt
# Use an injected input value, if present.
input ||= gets.chomp.downcase
case input
when "new" then instructions
when "load" then load_game
when "exit" then exit!
else introduction
end
end
This avoids the need to stub or mock an object in the first place. Your tests can now simply call #introduction with or without an explicit value. That allows you to spend your time testing your logic branches and method outputs, rather than writing a lot of scaffolding to support mocking of your IO#gets call or avoiding nil-related exceptions.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.