在尝试模拟Hash Elements的gets和puts时,RSpec无法定义单例错误
我有一个Book Model,它是一个
ruby脚本,可以为程序中提到的某些预定义书籍标题分配价格.以下是书籍模型的外观: –
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 can't be 0 or a negative integer or in decimal format or alphanumeric. nPlease input appropriate price 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 Details:#{book_details.books}******n" 我正在尝试编写一个测试用例,检查每个图书项目的正确价格输入.如果价格输入不当,则应要求用户重新输入价格.该计划做得很好.但是当我尝试使用RSpec模拟这种行为时,我遇到了困难. require 'spec_helper' describe Book do before :each do books = {"The Last Samurai" => nil,"Harry Potter and the Deathly Hallows" => nil} @book = Book.new(books) end describe "#new" do it "Should be an instance of the Book" do @book.should be_an_instance_of Book end 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 STDOUT.should_receive(:puts).and_return("Welcome to setting book price program") book_obj.get_prices.should_not be_nil book_obj.books["The Last Samurai"].stub!(:gets) {"40"} #trying to set the value for one book using Hash book_obj.books["The Last Samurai"].should == 40 #verifying the value set for a particular key is accurate end end end 你甚至可以从Github clone this code尝试这个.我使用的是Ruby 1.9.3和rspec 2.11.0 The error that I'm getting currently is:- Failures: 1) Book#getprice Should get the price in the correct format or else return appropriate error Failure/Error: book_obj.books["The Last Samurai"].stub!(:gets) {"40"} #trying to set the value for one book using Hash TypeError: can't define singleton # ./spec/book_spec.rb:31:in `block (3 levels) in <top (required)>' Finished in 7.61 seconds 2 examples,1 failure Failed examples: rspec ./spec/book_spec.rb:21 # Book#getprice Should get the price in the correct format or else return appropriate error 更新的问题 对于糟糕的用户输入,使用以下测试用例我收到以下错误.我怎样才能正确处理这个?我尝试了几种选择,但它们似乎都失败了.请参阅规范代码段中每个选项的注释. 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 integern 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 integern") #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 integern") #STDOUT.should == "Price cannot be 0 or a negative integer or in decimal format or alphanumeric. nPlease input appropriate duration in integern" end Failures: 1) Book#getprice Incorrect input format should return error message asking user to re input Failure/Error: 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 integern") (#<IO:0x00000001c7b298>).puts(any args) expected: 1 time received: 0 times # ./spec/book_spec.rb:40:in `block (3 levels) in <top (required)>' 我真的很感激任何指导如何做到这一点.谢谢. 解决方法
如果使用–backtrace标志运行规范,您将看到在
https://github.com/rspec/rspec-mocks/blob/v2.13.0/lib/rspec/mocks/method_double.rb#L140上引发错误,其中rspec-mocks正在尝试获取对象的单例类被存根或模拟.这适用于大多数类的实例,但规范中存在错误.
代码发送到STDIN,但规范是试图存取到book_obj.books [“The Last Samurai”],当时是一个int,你不能从int得到一个单例: $irb 1.9.3-p392 :001 > class << 1; self; end TypeError: can't define singleton from (irb):1 from /Users/david/.rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in `<main>' 如果我理解正确,您想进行两项更改.首先,将脚本的最后几行移动到一个单独的文件中,该文件在运行规范时不会被加载,例如bin / books(它可能需要book.rb然后添加这些行). 接下来,删除存根在book_obj.books [“The Last Samurai”]上获取的行,并在调用get_prices的行之前添加一条存根获取STDIN的行(这是与STDIN发生交互时): STDIN.stub(:gets) { "40" } book_obj.get_prices.should_not be_nil 这至少会让你的规格通过. 一般来说,直接处理w / STDIN和STDOUT的代码很难在对象级别进行规范,因为像rspec,minitest等测试工具都使用STDOUT来显示它们的信息,因此你最终会遇到很多令人困惑的噪音.贝壳.我建议更改设计以将输入/输出流注入书类(在运行脚本时可以是STDIN和STDOUT,但在运行rspec时测试可以加倍),或者使用像aruba这样设计的工具规范交互式shell脚本. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |