Как протестировать создание исключения в Rails / RSpec?

86

Вот такой код:

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

Хочу протестировать через RSpec. Мой код:

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

CarBrand с идентификатором, равным 0, не существует, поэтому мой код контроллера вызывает Errors :: CarBrandNotFound, но мой тестовый код сообщает мне, что ничего не было поднято. Как я могу это исправить? Что я не так?

малкоаури
источник

Ответы:

116

Чтобы специфицировать обработку ошибок, ваши ожидания должны быть установлены на блоке; оценка объекта не может вызвать ошибку.

Итак, вы хотите сделать что-то вроде этого:

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

Подробнее см. Ожидаемая ошибка .

Я немного удивлен, что вы не получаете никаких исключений из результатов вашей спецификации.

Якоб С
источник
1
@ jakob-s ожидаемое поведение ошибки, которое вы здесь используете, не работает с запросами контроллера. Сам по get :index, car_brand_id: 0себе не вызывает ошибки.
Рикардо Отеро,
@RicardoOtero: Возможно, все изменилось, но, что бы это ни стоило, он меняет : gist.github.com/koppen/0e1d0894a908a3768847 . Но, безусловно, что-то в стеке могло обрабатывать ошибку до того, как она перешла к исполнителю спецификации.
Jakob S
Это правильный ответ для текущих версий rspec, за которые следует проголосовать
Нил Вудс,
Это правильно. Правильная форма для проверки исключений - использование {} вместо () в методе except.
Луис Энрике
111

Используйте expect{}вместо expect().

kaleb4eg
источник
7
Стоит отметить, что это решает проблему, поскольку синтаксис {} создает блок для отслеживания возникновения данного исключения. MiniTest предъявляет аналогичные требования к синтаксису при проверке того, что блок кода вызывает исключение.
Argus9
1
Такое небольшое изменение, черт возьми. Принуждал меня какое-то время шлифовать круги. Спасибо за это.
Джош
4
Я не могу в это поверить. 1 час попыток, и он просто превращается ( )в { }! Большое спасибо
Саймон Франзен
1
Да, то же самое для меня - я думаю, что потратил больше :) из-за этого я опубликовал решение здесь
kaleb4eg
2
Я знаю, что мне следует использовать комментарии, чтобы задать вопрос ... но все же я хотел бы поблагодарить вас за ответ. После нескольких подходов я наконец нашел решение своей проблемы.
Флорин Лей
18

get :index никогда не вызовет исключения - он скорее установит ответ как ошибку 500, как это сделал бы настоящий сервер.

Вместо этого попробуйте:

it 'raises CarBrandNotFound exception' do
  controller.params[:car_brand_id] = 0
  expect{ controller.car_brand }.to raise_error(Errors::CarBrandNotFound)
end
BroiSatse
источник
1
Я рад, что кто-то об этом упомянул! :) Якоб пытался объяснить им, что это никогда не вызовет исключения в ответах, получивших наибольшее количество голосов, но он столкнулся с некорректным сопротивлением. 👍
Тарек Н. Эльсамни