2013-05-31 4 views
21

Mam metodę, która wykonuje pewne czynności na modelu Cat aw przypadku niewłaściwego wejścia podnosi wyjątek:Jak mogę "oczekiwać" czegoś, co podnosi wyjątek w RSpec?

context "hungry cat" do 
    it { expect { eat(what: nil) }.to raise_error } 
end 

Co chcę zrobić, to sprawdzić, czy metoda zmiana statusu Koty, tak jak:

context "hungry cat" do 
    it { expect { eat(what: nil) }.to raise_error } 
    it { expect { eat(what: nil) }.not_to change(cat, :status) } 
end 

Problem polega na tym, że ponieważ eat(what: nil) spowoduje zgłoszenie wyjątku, drugie it zakończy się niepowodzeniem bez względu na wszystko. Czy możliwe jest zignorowanie wyjątku i sprawdzenie jakiegoś warunku?

wiem, że to możliwe, aby zrobić coś takiego:

it do 
    expect do 
    begin 
     eat(what: nil) 
    rescue 
    end 
    end.not_to change(cat, :status) 
end 

Ale to jest zbyt brzydka.

+2

Co powiesz na "to {spodziewać się {zjeść (co: nil) zero ratunku} .not_to zmienić (cat,: status)}"? – awendt

+0

"dobry", czy możesz napisać to jako odpowiedź? – Andrew

+0

W 'Test/Unit', istnieje ładne twierdzenie," assert_raise ", myślę. –

Odpowiedz

18

Można użyć "rescue nil" idiom skrócić, co już masz:

it { expect { eat(what: nil) rescue nil }.not_to change(cat, :status) } 
+4

To działa, ale chciałbym, aby był sposób na rspec tego, np .: 'spodziewać {...} .ignoring_errors.to zmienić (cat,: status) ' –

0

Brzmi dziwnie, że kod eat(what: nil) nie jest uruchamiany oddzielnie dla każdego testu i ma wpływ na pozostałe. Nie jestem pewien, ale prawdopodobnie ponowne napisanie testów nieco rozwiąże problem lub dokładniej wskaże, gdzie jest problem (wybierz swój smak poniżej).

Korzystanie should:

context "hungry cat" do 
    context "when not given anything to eat" do 
    subject { -> { eat(what: nil) } } 
    it { should raise_error } 
    it { should_not change(cat, :status) } 
    end 
end 

Korzystanie expect:

context "hungry cat" do 
    context "when not given anything to eat" do 
    let(:eating_nothing) { -> { eat(what: nil) } } 
    it "raises an error" do 
     expect(eating_nothing).to raise_error 
    end 
    it "doesn't change cat's status" do 
     expect(eating_nothing).to_not change(cat, :status) 
    end 
    end 
end 
+0

Myślę, że źle zrozumiałeś pytanie. Jeśli 'eat' podniesie wyjątek, drugi przypadek zawsze się nie powiedzie, ponieważ wyjątek jest nieobsługiwany. – Andrew

+0

Może zrobiłem. Czy oczekiwane zachowanie w systemie ma nieobsługiwane wyjątki, które potencjalni użytkownicy mogą generować? Jeśli tak, czy możesz wyjaśnić, dlaczego, tutaj lub w edycji na twoje pytanie? –

+0

Tak, to jest oczywiście oczekiwane zachowanie, ponadto większość bibliotek ruby ​​może generować wyjątki, które powinny być obsługiwane przez ich użytkowników i to zachowanie powinno być przetestowane również. Na przykład. rails '#save!', 'Float ('aaa')', EOFError podczas 'File # read'. W moim przypadku chcę przetestować, że kontekst został pomyślnie przywrócony po zgłoszeniu wyjątku (wycofanie transakcji, zamknięcie deskryptorów itp.). – Andrew

12

W RSpec 3 możesz połączyć dwa testy w jeden. Uważam, że jest to bardziej czytelne niż podejście rescue nil.

it { expect { eat(what: nil) }.to raise_error.and not_to change(cat, :status)}

+4

Czy jesteś pewien, że to właściwa składnia? Daje mi błąd: 'NoMethodError: niezdefiniowana metoda 'not_to' dla # dombesz

+1

Nie, to nie zadziała, zobacz mój komentarz poniżej. –

11

Można chain pozytywne twierdzenia o and. Jeśli chcesz wymieszać negację w łańcuchu, RSpec 3.1 wprowadził define_negated_matcher.

Można zrobić coś takiego:

RSpec::Matchers.define_negated_matcher :avoid_changing, :change 

expect { eat(what: nil) } 
    .to raise_error 
    .and avoid_changing(cat, :status) 

Zainspirowany this comment.

+1

To jest naprawdę wielkie dzięki. Nie mogę uwierzyć, że wcześniej nie wpadłem na to. – adaam

+1

To powinna być dobra odpowiedź! –