例外情况RSpec

我有一个方法depart(plane) ,错误fail "The plane can't set off because it is stormy" if @weather.stormy? 。 这是在我的airport class定义的

 class Airport attr_accessor :planes, :landed, :weather def initialize(weather = Weather.new) #plane has no location when initialized @landed = nil @planes = [] @weather = weather end def land(plane) fail "You can't land this plane again!" if @landed == true @planes << plane @landed = true end def depart(plane) fail "The plane has already departed" if @landed == false fail "The plane can't set off because it is stormy" if @weather.stormy? @planes.pop puts "Your plane has left the airport!" @landed = false end end 

我也有飞机课:

 class Plane end 

方法.stormy? 是一种生成随机数的方法。 如果数字大于75,则会产生风暴,否则为假。 这是在我的weather class定义的

 def stormy? number > 70 ? true : false end def number rand(1..100) end 

我试图测试错误fail "The plane can't set off because it is stormy" if @weather.stormy? 使用RSpec。 我发现这非常困难,因为我对RSpec很新。

我遇到的问题是通过这个测试,因为风暴要么是真的,要么是假的。 如何预设值并进行测试?

我的整个airport_spec.rb文件:

 require 'airport' require 'plane' require 'weather' describe Airport do let(:airport) { Airport.new } let(:plane) { double :plane } let(:weather) { double :weather} #let(:weather) {double :weather} it 'creates new airports' do expect(:airport).to eq(:airport) end it 'accepts landed planes' do subject.land(:plane) expect(subject.landed).to be(true) end describe '#initialize' do it 'initializes a planes array when airport is instantiated' do expect(airport.planes).to be_an_instance_of(Array) end it 'initializes the plane to be landed to be nil upon instantiation' do expect(airport.landed).to be nil end it 'instantiates a new weather object upon initialization' do weather = airport.weather expect(airport.weather).to eq weather end end describe '#land' do it 'adds a plane to the planes array when landed' do subject.land(:plane) expect(subject.planes).to eq [:plane] end it 'will not land a plane that is already landed' do subject.land(:plane) expect {subject.land(:plane)}.to raise_error("You can't land this plane again!") end end describe '#depart' do it 'will not allow a plane to take off when it is stormy' do weather = Weather.new allow(weather).to receive(:stormy?).and_return true expect{subject.depart(plane)}.to raise_error("The plane can't set off because it is stormy") end end describe '#full' do it 'will raise an error when the airport is too full' do expect(subject.full?).to eq(true) end end end 

失败的测试:

  it 'will not allow a plane to take off when it is stormy' do weather = Weather.new allow(Airport.new).to receive(weather.stormy?).and_return true expect{subject.depart(plane)}.to raise_error("The plane can't set off because it is stormy") end end 

我为什么得到:

 Failures: 1) Airport#depart will not allow a plane to take off when it is stormy Failure/Error: expect{subject.depart(plane)}.to raise_error("The plane can't set off because it is stormy") expected Exception with "The plane can't set off because it is stormy" but nothing was raised # ./spec/airport_spec.rb:75:in `block (3 levels) in ' Finished in 0.02878 seconds (files took 0.15908 seconds to load) 12 examples, 1 failure RSpec version : 3.5.4 

我又跑了一次:

 Failures: 1) Airport#depart will not allow a plane to take off when it is stormy Failure/Error: expect{subject.depart(plane)}.to raise_error("The plane can't set off because it is stormy") expected Exception with "The plane can't set off because it is stormy" but nothing was raised # ./spec/airport_spec.rb:58:in `block (3 levels) in ' 2) Airport#depart removes a plane from the planes array when taken-off Failure/Error: fail "The plane can't set off because it is stormy" if @weather.stormy? RuntimeError: The plane can't set off because it is stormy # ./lib/airport.rb:20:in `depart' # ./spec/airport_spec.rb:63:in `block (3 levels) in ' Finished in 0.03361 seconds (files took 0.15734 seconds to load) 16 examples, 2 failures Failed examples: rspec ./spec/airport_spec.rb:56 # Airport#depart will not allow a plane to take off when it is stormy rspec ./spec/airport_spec.rb:61 # Airport#depart removes a plane from the planes array when taken-off 

但是,有时它会起作用并通过:

 COVERAGE: 100.00% -- 76/76 lines in 6 files Benjamins-MacBook-Pro:airport_challenge benjamin$ rspec Airport creates new airports accepts landed planes #initialize initializes a planes array when airport is instantiated initializes the plane to be landed to be nil upon instantiation instantiates a new weather object upon initialization #land adds a plane to the planes array when landed will not land a plane that is already landed #depart will not allow a plane to take off when it is stormy #full will raise an error when the airport is too full Plane creates new planes Weather creates a weather object #number will create a random number #storm will either be stormy or sunny Have you considered running rubocop? It will help you improve your code! Try it now! Just run: rubocop Finished in 0.01254 seconds (files took 0.15439 seconds to load) 13 examples, 0 failures COVERAGE: 96.05% -- 73/76 lines in 6 files +----------+----------------+-------+--------+---------+ | coverage | file | lines | missed | missing | +----------+----------------+-------+--------+---------+ | 83.33% | lib/airport.rb | 18 | 3 | 25-27 | +----------+----------------+-------+--------+---------+ 5 file(s) with 100% coverage not shown 

当你说allow(Airport.new).to receive...这是设置一个新的Airport而不是指你使用let设置的那个。

stormy? 方法是在Weather所以期望应该是:

 allow(weather).to receive(:stormy?).and_return true 

并设置测试对象使用嘲笑stormy?的天气stormy? 方法:

 let(:weather) { double :weather } subject { Airport.new(weather) } 

作为侧面说明, receive采用将被调用的方法的名称 。 当你写receive(weather.stormy?) RSpec正试图转换来自weather.stormy?返回值 weather.stormy? (将为TrueFalse )成为用作方法名称的符号,因此undefined method to_sym’`。


查看规范的完整版本,您目前是一个隐含的主题,即基于describe Airport... RSpec创建了一个Airport使用Airport.new (没有参数)成为您的规范的主题。 这意味着主体没有使用你躲过stormy?weather物体stormy? 方法等你真正的stormy? 方法仍在使用中。 这就是我使用subject { Airport.new(weather) }设置明确主题的原因。 最后,您不希望在测试中设置本地weatherweather = Weather.new ),因为您希望allow(weather)...从传递给测试主题的let中引用天气。


这是规范的完整版本,其中包含所做的更改:

 require 'airport' describe Airport do let(:weather) { double :weather } subject { Airport.new(weather) } let(:plane) { double :plane } it 'will not allow a plane to take off when it is stormy' do allow(weather).to receive(:stormy?).and_return true expect { subject.depart(plane) }.to raise_error("The plane can't set off because it is stormy") end end