Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
297 views
in Technique[技术] by (71.8m points)

ruby - Rspec: expect vs expect with block - what's the difference?

Just learning rspec syntax and I noticed that this code works:

  context "given a bad list of players" do
    let(:bad_players) { {} }

    it "fails to create given a bad player list" do
       expect{ Team.new("Random", bad_players) }.to raise_error
     end 
  end

But this code doesn't:

  context "given a bad list of players" do
    let(:bad_players) { {} }

    it "fails to create given a bad player list" do
       expect( Team.new("Random", bad_players) ).to raise_error
     end 
  end

It gives me this error:

Team given a bad list of players fails to create given a bad player list
     Failure/Error: expect( Team.new("Random", bad_players) ).to raise_error
     Exception:
       Exception
     # ./lib/team.rb:6:in `initialize'
     # ./spec/team_spec.rb:23:in `new'
     # ./spec/team_spec.rb:23:in `block (3 levels) in <top (required)>'

My question is:

  1. Why does this happen?
  2. What is the difference between the former and later example exactly in ruby?

I am also looking for rules on when to use one over the other

One more example of the same but inverse results, where this code works:

  it "has a list of players" do
    expect(Team.new("Random").players).to be_kind_of Array
  end 

But this code fails

  it "has a list of players" do
    expect{ Team.new("Random").players }.to be_kind_of Array
  end

Error I get in this case is:

Failure/Error: expect{ Team.new("Random").players }.to be_kind_of Array
       expected #<Proc:0x007fbbbab29580@/Users/amiterandole/Documents/current/ruby_sandbox/tdd-ruby/spec/team_spec.rb:9> to be a kind of Array
     # ./spec/team_spec.rb:9:in `block (2 levels) in <top (required)>'

The class I am testing looks like this:

class Team
  attr_reader :name, :players

  def initialize(name, players = [])
    raise Exception unless players.is_a? Array

    @name = name
    @players = players
  end
end
question from:https://stackoverflow.com/questions/19960831/rspec-expect-vs-expect-with-block-whats-the-difference

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

As has been mentioned:

expect(4).to eq(4)

This is specifically testing the value that you've sent in as the parameter to the method. When you're trying to test for raised errors when you do the same thing:

expect(raise "fail!").to raise_error

Your argument is evaluated immediately and that exception will be thrown and your test will blow up right there.

However, when you use a block (and this is basic ruby), the block contents isn't executed immediately - it's execution is determined by the method you're calling (in this case, the expect method handles when to execute your block):

expect{raise "fail!"}.to raise_error

We can look at an example method that might handle this behavior:

def expect(val=nil)
  if block_given?
    begin
      yield
    rescue
      puts "Your block raised an error!"
    end
  else
    puts "The value under test is #{val}"
  end
end

You can see here that it's the expect method that is manually rescuing your error so that it can test whether or not errors are raised, etc. yield is a ruby method's way of executing whatever block was passed to the method.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...