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
?
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
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
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.
You could inject the IO dependency. gets
reads from STDIN
, which is class IO
. If you inject another IO
object into your class, you can use StringIO
in your tests. Something like this:
class Whatever
attr_reader :action
def initialize(input_stream, output_stream)
@input_stream = input_stream
@output_stream = output_stream
end
def welcome_user
@output_stream.puts "Welcome! What would you like to do?"
@action = get_input
end
private
def get_input
@input_stream.gets.chomp
end
end
Tests:
require 'test/unit'
require 'stringio'
require 'whatever'
class WhateverTest < Test::Unit::TestCase
def test_welcome_user
input = StringIO.new("something\n")
output = StringIO.new
whatever = Whatever.new(input, output)
whatever.welcome_user
assert_equal "Welcome! What would you like to do?\n", output.string
assert_equal "something", whatever.action
end
end
This allows your class to interact with any IO stream (TTY, file, network, etc.).
To use it on the console in production code, pass in STDIN
and STDOUT
:
require 'whatever'
whatever = Whatever.new STDIN, STDOUT
whatever.welcome_user
puts "Your action was #{whatever.action}"
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.