I have a Book Model which is a ruby script that assigns prices to
certain predefined Book titles mentioned in the program. I’m using Ruby
1.9.3-p327 and rspec 2.11.0
#class RspecLoopStop < Exception; end
class Book
attr_accessor :books
def initialize books
puts "Welcome to setting book price program"
@books = books
end
def get_prices
puts "Please enter appropriate price for each book item:-"
count = 0
@books = @books.inject({}) { |hash, book|
print "#{book.first}: "
price = STDIN.gets.chomp
while (price !~ /^[1-9]\d*$/ && price != "second hand")
puts "Price cannot be 0 or a negative integer or in decimal
format or alphanumeric. \nPlease input appropriate duration in integer"
price = STDIN.gets.chomp #gets.chomp - throws error
end
price == “second hand” ? price = “100” : price #takes a
default price
hash[book.first] = price.to_i
hash
}
end
end
books = {"The Last Samurai" => nil,
"Ruby Cookbook" => nil,
"Rails Recipes" => nil,
"Agile Development with Rails" => nil,
"Harry Potter and the Deathly Hallows" => nil}
book_details = Book.new(books)
book_details.get_prices
#puts "\n*******Books:#{book_details.books}******\n"
If a user inputs any alphanumeric data or negative number or 0 or
anything having decimals, as per the program the user is asked to enter
only a positive integer for the price of each book. I’ve tried to mock
this behavior using RSpec.
My current challenge is how to catch the wrong user input, the message
that comes along with and handle it appropriately so that the spec
should pass. I’ve tried a couple of things but the below spec currently
runs into an infinite loop with input price given in the wrong format.
PFB my spec.
require 'spec_helper'
describe Book do
before :each do
books = {"The Last Samurai" => nil,
"Ruby Cookbook" => nil,
"Rails Recipes" => nil,
"Agile Development with Rails" => nil,
"Harry Potter and the Deathly Hallows" => nil}
@book = Book.new(books)
end
describe "#getprice" do
it "Should get the price in the correct format or else return
appropriate error" do
puts
“\n************************************************************************\n”
book_obj = @book
STDIN.stub(:gets) { “40” }
book_obj.get_prices.should_not be_nil
end
it "Incorrect input format should return error message asking
user to re input" do
puts
“\n************************************************************************\n”
book_obj = @book
#STDIN.stub(:gets) { “40abc” }
#book_obj.get_prices.should be_nil --> adding this line of
code goes into an infinite loop with the error message below
#Price cannot be 0 or a negative integer or in decimal format
or alphanumeric. \nPlease input appropriate duration in integer\n
#STDOUT.should_receive(:puts).and_return("Price cannot be 0 or
a negative integer or in decimal format or alphanumeric. \nPlease input
appropriate duration in integer\n")
#the below two tests fails with syntax error - don't seem that
easy to figure out what’s going wrong
#STDOUT.should_receive("Price cannot be 0 or a negative
integer or in decimal format or alphanumeric. \nPlease input appropriate
duration in integer\n")
#\n towards the end is as in the third line of input the user
is asked to re enter input in correct format
#STDOUT.should == “Price cannot be 0 or a negative integer or
in decimal format or alphanumeric. \nPlease input appropriate duration
in integer\n”
#begin #didn't work for me
# STDIN.stub(:gets) { "40abc" }
# book_obj.get_prices.should_raise RspecLoopStop
#rescue RspecLoopStop
# #exit
#end
begin
STDIN.stub(:gets) { "40abc" } #incorrect input prompts user
to re enter price in correct format
book_obj.get_prices #how to catch the infinite loop as an
exception and exit out of it say using rescue block
rescue #I guess this won’t be called until the exception is
correctly caught
STDIN.stub(:gets) { “85” }
book_obj.get_prices.should_not be_nil
end
end
end
end
Can anyone please point me in the right direction on how can I handle
this correctly. I’m able to mock the user being asked to re enter data
for wrong input. My question is how can I stop that(as per the actual
program logic) upon correct input as part of the spec.
I did try one of the suggestions from a similar question, but it
doesn’t seem to be working for me. I could be missing something. The
code is also available to be cloned from Github. Thank you.