例外情况RSpec

时间:2017-09-03 17:40:50

标签: ruby 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

我正在尝试使用RSpec测试错误fail "The plane can't set off because it is stormy" if @weather.stormy?。我发现这非常困难,因为我对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 <top (required)>'

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 <top (required)>'

  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 <top (required)>'

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

1 个答案:

答案 0 :(得分:0)

当您说allow(Airport.new).to receive...这是设置新Airport时,指的是您使用let设置的那个。

stormy?方法在Weather上,因此预期应为:

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

并设置测试主题以使用模拟的stormy?方法使用天气:

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

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

查看规范的完整版本,您目前是隐式主题,即基于describe Airport... RSpec使用Airport创建了Airport.new(没有参数)成为您的规范的主题。这意味着主题未使用您weather方法存在的stormy?对象,因此仍然使用了真正的stormy?方法。这就是我使用subject { Airport.new(weather) }设置显式主题的原因。最后,您不希望在测试中设置本地weatherweather = Weather.new),因为您希望allow(weather)...引用已通过的let天气对测试对象。<​​/ p>

这是规范的完整版本,并进行了更改:

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