bod*_*tva 4 io hash mocking rspec2 ruby-1.9.3
我有一个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"
Run Code Online (Sandbox Code Playgroud)
我正在尝试编写一个测试用例,检查每个图书项目的正确价格输入.如果价格输入不当,则应要求用户重新输入价格.该计划做得很好.但是当我尝试使用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 "#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
Run Code Online (Sandbox Code Playgroud)
你甚至可以从Github 克隆这个代码来试试这个.我使用的是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
Run Code Online (Sandbox Code Playgroud)
更新的问题
对于糟糕的用户输入,使用以下测试用例我收到以下错误.我怎样才能正确处理这个?我尝试了几种选择,但它们似乎都失败了.请参阅规范代码段中每个选项的注释.
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")
#STDOUT.should == "Price cannot be 0 or a negative integer or in decimal format or alphanumeric. \nPlease input appropriate duration in integer\n"
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 integer\n")
(#<IO:0x00000001c7b298>).puts(any args)
expected: 1 time
received: 0 times
# ./spec/book_spec.rb:40:in `block (3 levels) in <top (required)>'
Run Code Online (Sandbox Code Playgroud)
我真的很感激任何指导如何做到这一点.谢谢.
如果您运行带有该--backtrace
标志的规范,您将在https://github.com/rspec/rspec-mocks/blob/v2.13.0/lib/rspec/mocks/method_double.rb#L140上看到该错误.,其中rspec-mocks试图获取对象的单例类被存根或模拟.这适用于大多数类的实例,但规范中存在错误.
该代码发送gets
到STDIN
,但规范试图存根gets
上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>'
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,您想进行两项更改.首先,将脚本的最后几行移动到一个单独的文件中,当您运行规范例如bin/books时它不会被加载(它可能需要book.rb然后添加这些行).
接着,移除短截线线路gets
上book_obj.books["The Last Samurai"]
,并添加一短截线线路gets
上STDIN
,而不是,之前调用该线get_prices
(这是当所述交互瓦特/ STDIN
发生):
STDIN.stub(:gets) { "40" }
book_obj.get_prices.should_not be_nil
Run Code Online (Sandbox Code Playgroud)
这至少会让你的规格通过.
在一般情况下,代码,涉及W/STDIN
和STDOUT
直接是很难在对象级别符合规范,因为测试工具,如RSpec的,MINITEST等,都使用STDOUT
提出自己的信息,所以你最终在shell很多混乱的噪音.我建议要么改变设计注入输入/输出流的书类(可STDIN
与STDOUT
当您运行脚本,但测试双打当你运行RSpec的),或者使用类似的工具阿鲁巴,其设计符合规范交互式shell脚本.
归档时间: |
|
查看次数: |
6993 次 |
最近记录: |