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:
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
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.
In the first case, when you pass a block to expect
, the execution of the block doesn't occur until it's time to evaluate the result, at which point the RSpec code can catch any error that are raised and check it against the expectation.
In the second case, the error is raised when the argument to expect
is evaluated, so the expect
code has no chance to get involved.
As for rules, you pass a block or a Proc
if you're trying to test behavior (e.g. raising errors, changing some value). Otherwise, you pass a "conventional" argument, in which case the value of that argument is what is tested.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With