Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I test a function with gets.chomp in it?

I have a simple function using gets.chomp like this:

def welcome_user
   puts "Welcome! What would you like to do?"
   action = gets.chomp
end 

I'd like to test it using ruby's built in TestCase suite like this:

class ViewTest < Test::Unit::TestCase
   def test_welcome
      welcome_user      
   end 
end 

The problem is, when I run that test, the gets.chomp stops the test because it needs the user to enter in something. Is there a way I can simulate user inputs using just ruby?

like image 481
user886596 Avatar asked Jun 05 '13 19:06

user886596


People also ask

How does the gets chomp work?

“gets” is a method that asks the user to input something. “chomp” is a method that removes the blank line that is automatically created by “gets” after the input.

Why we use gets chomp in Ruby?

chomp! is a String class method in Ruby which is used to returns new String with the given record separator removed from the end of str (if present). chomp method will also removes carriage return characters (that is it will remove \n, \r, and \r\n) if $/ has not been changed from the default Ruby record separator, t.


2 Answers

You could create a pipe and assign its "read end" to $stdin. Writing to the pipe's "write end" then simulates user input.

Here's an example with a little helper method with_stdin for setting up the pipe:

require 'test/unit'

class View
  def read_user_input
    gets.chomp
  end
end

class ViewTest < Test::Unit::TestCase
  def test_read_user_input
    with_stdin do |user|
      user.puts "user input"
      assert_equal(View.new.read_user_input, "user input")
    end
  end

  def with_stdin
    stdin = $stdin             # remember $stdin
    $stdin, write = IO.pipe    # create pipe assigning its "read end" to $stdin
    yield write                # pass pipe's "write end" to block
  ensure
    write.close                # close pipe
    $stdin = stdin             # restore $stdin
  end
end
like image 85
Stefan Avatar answered Nov 17 '22 16:11

Stefan


You first separate the 2 concerns of the method:

def get_action
  gets.chomp
end

def welcome_user
  puts "Welcome to Jamaica and have a nice day!"
  action = get_action
  return "Required action was #{action}."
end

And then you test the second one separately.

require 'minitest/spec'
require 'minitest/autorun'

describe "Welcoming users" do
  before do
    def get_action; "test string" end
  end

  it "should work" do
    welcome_user.must_equal "Required action was test string."
  end
end

As for the first one, you can

  1. Test it by hand and rely that it won't break (recommended approach, TDD is not a religion).
  2. Get the subverted version of the shell in question and make it imitate the user, and compare whether get_action indeed gets what the user types.

While this is a practical answer to your problem, I do not know how to do 2., I only know how to imitate the user behind the browser (watir-webdriver) and not behind the shell session.

like image 45
Boris Stitnicky Avatar answered Nov 17 '22 17:11

Boris Stitnicky