Writing a test for a case statement in Ruby

1.8k Views Asked by At

I'm trying to write a test for a case statement using minitest. Would I need to write separate tests for each "when"? I included my code below. Right now it just puts statements, but eventually it's going to redirect users to different methods. Thanks!

require 'pry'
require_relative 'messages'

class Game
  attr_reader :user_answer

  def initialize(user_answer = gets.chomp.downcase)
    @user_answer = user_answer
  end

  def input
    case user_answer
    when "i"
      puts "information"
    when "q"
      puts "quitter"
    when "p"
      puts "player play"
    end
  end
end
2

There are 2 best solutions below

1
On BEST ANSWER

This answer will help you. Nonetheless I'll post one way of applying it to your situation. As suggested by @phortx when initializing a game, override the default user-input with the relevant string. Then by using assert_output we can do something like:

#test_game.rb
require './game.rb'         #name and path of your game script
require 'minitest/autorun'  #needed to run tests

class GameTest < MiniTest::Test

  def setup
    @game_i = Game.new("i")  #overrides default user-input
    @game_q = Game.new("q")
    @game_p = Game.new("p")
  end

  def test_case_i
    assert_output(/information\n/) {@game_i.input}
  end

  def test_case_q
    assert_output(/quitter\n/) {@game_q.input}
  end

  def test_case_p
    assert_output(/player play\n/) {@game_p.input}
  end
end

Running the tests...

$ ruby test_game.rb
#Run options: --seed 55321

## Running:

#...

#Finished in 0.002367s, 1267.6099 runs/s, 2535.2197 assertions/s.

#3 runs, 6 assertions, 0 failures, 0 errors, 0 skips
3
On

You have to test each case branch. Via RSpec it would work that way:

describe Game do
  subject { Game }

  describe '#input' do
     expect_any_instance_of(Game).to receive(:puts).with('information')
     Game.new('i').input

     expect_any_instance_of(Game).to receive(:puts).with('quitter')
     Game.new('q').input

     expect_any_instance_of(Game).to receive(:puts).with('player play')
     Game.new('p').input
    end
end

However due the fact that puts is ugly to test, you should refactor your code to something like that:

require 'pry'
require_relative 'messages'

class Game
  attr_reader :user_answer

  def initialize(user_answer = gets.chomp.downcase)
    @user_answer = user_answer
  end

  def input
    case user_answer
    when "i"
     "information"
    when "q"
      "quitter"
    when "p"
      "player play"
    end
  end

  def print_input
    puts input
  end
end

Then you can test with RSpec via:

describe Game do
  subject { Game }

  describe '#print_input' do
    expect_any_instance_of(Game).to receive(:puts).with('quitter')
    Game.new('q').print_input
  end

  describe '#input' do
     expect(Game.new('i').input).to eq('information')
     expect(Game.new('q').input).to eq('quitter')
     expect(Game.new('i').input).to eq('player play')
     expect(Game.new('x').input).to eq(nil)
  end
end