Як протестувати створення винятків у Rails / RSpec?


84

Існує такий код:

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, за які слід проголосувати
Ніл Вудс

Це правильно. Правильною формою для перевірки винятків є використання {} замість () у методі osim.
Луїс Енріке

109

Використовуйте expect{}замість expect().


7
Варто зазначити, що це вирішує проблему, оскільки синтаксис {} створює блок для моніторингу для підняття даного винятку. MiniTest має подібні вимоги до синтаксису, коли перевіряє, що блок коду викликає виняток.
Аргус, 9

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

1
Я рада, що хтось про це згадав! :) Якоб намагався виховувати їх у тому, що це ніколи не призведе до винятку у найголоснішій відповіді, але він зіткнувся з деяким неправильним опором. 👍
Тарек Н.Ельсамні,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.