Jak przetestować zgłaszanie wyjątków w Rails / RSpec?

86

Jest następujący kod:

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

Chcę to przetestować przez RSpec. Mój kod to:

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

CarBrand z identyfikatorem równym 0 nie istnieje, dlatego mój kod kontrolera zgłasza Errors :: CarBrandNotFound, ale mój kod testowy mówi mi, że nic nie zostało zgłoszone. Jak mogę to naprawić? Co się mylę?

malcoauri
źródło

Odpowiedzi:

116

Aby określić obsługę błędów, Twoje oczekiwania muszą być ustawione w bloku; ocena obiektu nie może spowodować błędu.

Więc chcesz zrobić coś takiego:

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

Aby uzyskać szczegółowe informacje, zobacz Oczekiwany błąd .

Jestem jednak trochę zaskoczony, że nie ma żadnego wyjątku, który spotyka się z wynikami specyfikacji.

Jakob S
źródło
1
@ jakob-s oczekiwane zachowanie błędu, którego tutaj używasz, nie działa w przypadku żądań kontrolera. Samo w get :index, car_brand_id: 0sobie nie powoduje błędu.
Ricardo Otero
@RicardoOtero Rzeczy mogły się zmienić, ale dla mnie to jest warte: gist.github.com/koppen/0e1d0894a908a3768847 . Ale z pewnością coś w stosie może obsługiwać błąd, zanim pojawi się on w specyfikacji.
Jakob S
To jest właściwa odpowiedź na aktualne wersje rspec, które powinny zostać przegłosowane
Neil Woods
To jest poprawne. Poprawną formą do testowania wyjątków jest użycie {} zamiast () w metodzie except.
Luiz Henrique
112

Użyj expect{}zamiast expect().

kaleb4eg
źródło
7
Warto zauważyć, że rozwiązuje to problem, ponieważ składnia {} tworzy blok do monitorowania, czy dany wyjątek ma zostać zgłoszony. MiniTest ma podobne wymagania dotyczące składni podczas sprawdzania, czy blok kodu wywołuje wyjątek.
Argus9
1
Taka mała cholerna zmiana. Przez jakiś czas szlifowałem koła. Dzięki za to.
josh
4
Nie mogę w to uwierzyć. 1 godzina próby, a to jest po prostu obracając ( )się { }! Dziękuję bardzo
Simon Franzen,
1
Tak, dla mnie to samo - wydaje mi się, że wydałem więcej :) z tego powodu zamieściłem tutaj rozwiązanie
kaleb4eg
2
Wiem, że powinienem używać komentarzy, aby zapytać ... ale mimo wszystko chciałbym podziękować za odpowiedź. Po wielu podejściach w końcu znalazłem rozwiązanie mojego problemu.
Florin Lei
18

get :index nigdy nie zgłosi wyjątku - raczej ustawi odpowiedź na błąd 500 w taki sposób, jak zrobiłby to prawdziwy serwer.

Zamiast tego spróbuj:

it 'raises CarBrandNotFound exception' do
  controller.params[:car_brand_id] = 0
  expect{ controller.car_brand }.to raise_error(Errors::CarBrandNotFound)
end
BroiSatse
źródło
1
Cieszę się, że ktoś o tym wspomniał! :) Jakob próbował ich uświadomić, że w najbardziej pozytywnej odpowiedzi nigdy nie będzie to wyjątek, ale napotkał niewłaściwy opór. 👍
Tarek N. Elsamni