本文介绍了异常 异常 RSpec的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个方法depart(plane),如果@weather.stormy?,它会出现错误fail飞机无法起飞,因为有暴风雨".这是在我的 airport class

I have a method depart(plane) which takes an error fail "The plane can't set off because it is stormy" if @weather.stormy?. This is defined in my 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,则生成风暴,否则为 false.这是在我的 weather class

The method .stormy? is a method in which a random number is generated. If the number is above 75, a storm is generated otherwise it is false. This is defined in my weather class

def stormy?
    number > 70 ? true : false
end

def number
    rand(1..100)
end

如果@weather.stormy?使用RSpec,我正在尝试测试错误fail飞机无法起飞,因为它是暴风雨".我发现这非常困难,因为我对 RSpec 非常陌生.

I am trying to test the error fail "The plane can't set off because it is stormy" if @weather.stormy?using RSpec. I am finding this extremely difficult as I am very new to RSpec.

我遇到的问题是通过这个测试,因为风暴可能是真的,也可能是假的.如何预设值并对其进行测试?

The problem I am having is passing this test as the storm either can be true or false. How can I preset a value and test it?

我的整个 airport_spec.rb 文件:

My whole airport_spec.rb file:

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

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

However, sometimes it works and passes:

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... 时,这是在设置新的 Airportnot 指的是您使用 let 设置的那个.

When you say allow(Airport.new).to receive... this is setting up a new Airport, not referring to the one you've set up using let.

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

The stormy? method is on Weather so the expectation should be:

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

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

and set up the test subject to use the weather with the mocked stormy? method:

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

作为补充说明,receive 使用将被调用的方法的名称.当您编写 receive(weather.stormy?) 时,RSpec 正在尝试从 weather.stormy?(这将是 TrueFalse) 转换成一个符号用作方法名称,因此 undefined methodto_sym'`.


As a side explanation, receive takes the name of a method that will be called. When you write receive(weather.stormy?) RSpec is trying to convert the return value from weather.stormy? (which would be True or False) into a symbol to use as the method name, hence undefined methodto_sym'`.

查看您的规范的完整版本,您目前是一个隐式主体,即基于 describe Airport... RSpec 创建了一个 Airport 使用 Airport.new(不带参数)作为规范的主题.这意味着主题没有使用 weather 对象,你在其中存根了 stormy? 方法,所以你真正的 stormy? 方法是仍在使用.这就是为什么我使用 subject { Airport.new(weather) } 设置一个 显式主题.最后,您不想在测试中设置本地 weather (weather = Weather.new),因为您想要 allow(weather)... 引用传递给测试对象的 let 中的天气.

Looking at the full version of your spec, you are currently an implicit subject i.e. based on the describe Airport... RSpec has created an Airport using Airport.new (with no arguments) to be the subject of your spec. This means that the subject isn't using the weather object where you've stubbed the stormy? method and so your real stormy? method is still being used. This is why I set up an explicit subject using subject { Airport.new(weather) }. Lastly, you don't want to be setting up a local weather in the test (weather = Weather.new) because you want allow(weather)... to refer to the weather from the let that's passed to the test subject.

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

Here's a complete version of the spec with the changes made:

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

这篇关于异常 异常 RSpec的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-22 03:08