web-dev-qa-db-ja.com

RSpecで例外を発生させるものをどのように「期待」しますか?

Catモデルでいくつかのアクションを実行するメソッドがあり、入力が正しくない場合に例外が発生します。

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

私がしたいのは、このメソッドが猫のステータスを変更するかどうかを確認することです:

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

問題は、eat(what: nil)が例外を発生させるため、2番目のitは何があっても失敗することです。それで、例外を無視していくつかの条件をチェックすることは可能ですか?

私は次のようなことが可能であることを知っています:

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

しかし、それはあまりにも醜いです。

33
Andrew

「rescue nil」イディオムを使用して、すでに持っているものを短くすることができます。

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

chain 肯定的なアサーションはandでできます。チェーンで否定されたものを混ぜたい場合、RSpec 3.1は define_negated_matcher

あなたは次のようなことをすることができます:

RSpec::Matchers.define_negated_matcher :avoid_changing, :change

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

このコメント に触発されました。

23
Jan Klimo

RSpec 3では、2つのテストを1つにチェーンできます。これは_rescue nil_アプローチよりも読みやすいと思います。

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

12
Sean

期待ブロック内に期待を置くこともできます。それはまだ少し醜いですが、うまくいくはずです:

expect do
  # including the error class is just good practice
  expect { cat.eat(what: nil) }.to raise_error(ErrorClass) 
end.not_to change { cat.status }
0
PJSCopeland

eat(what: nil)コードが各テストに対して個別に実行されておらず、他のテストに影響しているのは奇妙に聞こえます。確かではありませんが、テストを少し書き直すだけで問題が解決するか、問題の場所をより正確に特定できます(以下のフレーバーを選択してください)。

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

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
Paul Fioravanti