Как поймать имитированное поведение бесконечного цикла и обработать его с помощью спасательного блока с помощью RSpec

У меня есть модель книги, которая представляет собой рубиновый скрипт, который назначает цены для определенных предопределенных названий книг, упомянутых в программе. Я использую Ruby 1.9.3-p327 и 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"

Если пользователь вводит какие-либо буквенно-цифровые данные, или отрицательное число, или 0, или что-либо с десятичными знаками, в соответствии с программой пользователю предлагается ввести только положительное целое число для цены каждой книги. Я пытался издеваться над этим поведением, используя RSpec.

Моя текущая задача состоит в том, как поймать неправильный пользовательский ввод, сообщение, которое приходит вместе с ним, и обработать его соответствующим образом, чтобы спецификация прошла. Я пробовал несколько вещей, но приведенная ниже спецификация в настоящее время приводит к бесконечному циклу с входной ценой, указанной в неправильном формате. ПФБ моя спец.

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

Может ли кто-нибудь указать мне в правильном направлении, как я могу справиться с этим правильно. Я могу издеваться над пользователем, которого просят повторно ввести данные для неправильного ввода. Мой вопрос в том, как я могу остановить это (согласно фактической логике программы) при правильном вводе как части спецификации.

Я попробовал одно из предложений из аналогичный вопрос, но, похоже, он у меня не работает. Я мог что-то упустить. код также доступен для клонирования с Github. Спасибо.


person boddhisattva    schedule 20.07.2013    source источник