例外情况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?
(将为True
或False
)成为用作方法名称的符号,因此undefined method
to_sym’`。
查看规范的完整版本,您目前是一个隐含的主题,即基于describe Airport...
RSpec创建了一个Airport
使用Airport.new
(没有参数)成为您的规范的主题。 这意味着主体没有使用你躲过stormy?
的weather
物体stormy?
方法等你真正的stormy?
方法仍在使用中。 这就是我使用subject { Airport.new(weather) }
设置明确主题的原因。 最后,您不希望在测试中设置本地weather
( weather = 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