ChatGPT解决这个技术问题 Extra ChatGPT

How to test exception raising in Rails/RSpec?

There is the following code:

def index
    @car_types = car_brand.car_types
end

def car_brand
    CarBrand.find(params[:car_brand_id])
    rescue ActiveRecord::RecordNotFound
        raise Errors::CarBrandNotFound.new 
end

I want to test it through RSpec. My code is:

it 'raises CarBrandNotFound exception' do
    get :index, car_brand_id: 0
    expect(response).to raise_error(Errors::CarBrandNotFound)
end

CarBrand with id equaling 0 doesn't exist, therefore my controller code raises Errors::CarBrandNotFound, but my test code tells me that nothing was raised. How can I fix it? What do I wrong?


G
Grzegorz

Use expect{} instead of expect().

Example:

it do 
  expect { response }.to raise_error(Errors::CarBrandNotFound)
end

It's worth pointing out that this solves the issue because the {} syntax creates a block to monitor for the given exception to be raised. MiniTest has similar syntax requirements when checking that a block of code raises an exception.
I can't believe it. 1 hour of trying and it's just turning ( ) into { }! Thank you so much
I wasn't able to get this method working in Rails 7
J
Jakob S

In order to spec error handling, your expectations need to be set on a block; evaluating an object cannot raise an error.

So you want to do something like this:

expect {
  get :index, car_brand_id: 0
}.to raise_error(Errors::CarBrandNotFound)

See Expect error for details.

I am a bit surprised that you don't get any exception bubbling up to your spec results, though.


@jakob-s the expect error behaviour that you're using here doesn't work on controller requests. The get :index, car_brand_id: 0 itself doesn't raise an error.
@RicardoOtero Things might have changed, but for what it's worth, it does for me: gist.github.com/koppen/0e1d0894a908a3768847. But certainly, something in the stack might be handling the error before it bubbles up to the spec runner.
This is the right answer for current rspec versions ans should be voted up
That is correct. The correct form to to test exceptions is using {} instead of () on except method.
B
BroiSatse

get :index will never raise an exception - it will rather set response to be an 500 error some way as a real server would do.

Instead try:

it 'raises CarBrandNotFound exception' do
  controller.params[:car_brand_id] = 0
  expect{ controller.car_brand }.to raise_error(Errors::CarBrandNotFound)
end

I'm glad that someone mentioned this! :) Jakob tried to educate them that it will never raise an exception in the most upvoted answer but he was faced with some incorrect resistance. 👍