Search code examples
ruby-on-railstestingrspecrspec-rails

Rspec raise matcher not working, copied syntax from docs?


rspec-core (3.9.1)
rspec-expectations (3.9.0)
rspec-mocks (3.9.1)
rspec-rails (4.0.0.beta4, 3.9.0)
rspec-support (3.9.2)

According to docs: https://relishapp.com/rspec/rspec-expectations/v/3-9/docs/built-in-matchers/raise-error-matcher, this should work:

expect { raise StandardError }.to raise_error

Yet in my code, when I run JUST that spec by itself, I get:

Failures:

  1) time rules should work
     Failure/Error: expect(raise StandardError).to raise_error
     
     StandardError:
       StandardError
     # ./spec/models/time_rules_spec.rb:87:in `block (2 levels) in <top (required)>'

Solution

  • Look closely at the error:

    Failure/Error: expect(raise StandardError).to raise_error
    

    That indicates that your failing test looks like this:

    it '...' do
      expect(raise StandardError).to raise_error
    end
    

    when it should look like this:

    it '...' do
      expect { raise StandardError }.to raise_error
    end
    

    Your version is equivalent to:

    result = raise StandardError
    expect(result).to raise_error
    

    so the raise is triggered before raise_error can trap and check for the exception. If you pass a block to expect as in the documentation:

    expect { raise StandardError }.to raise_error
    

    then the raise_error matcher will have everything set up to trap and check for the exception.


    As an aside, you'll probably want to be more explicit with your raise_error matcher:

    expect { raise StandardError }.to raise_error(StandardError)
    

    to avoid an overly-broad matcher and a warning like this:

    WARNING: Using the raise_error matcher without providing a specific error or message risks false positives, since raise_error will match when Ruby raises a NoMethodError, NameError or ArgumentError, potentially allowing the expectation to pass without even executing the method you are intending to call.