Подтвердить что ты не робот

Как "ожидать" чего-то, что вызывает исключение в 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) вызовет исключение, второй it будет терпеть неудачу, несмотря ни на что. Итак, можно ли игнорировать исключение и проверить какое-то условие?

Я знаю, что можно сделать что-то вроде:

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

Но это слишком уродливо.

4b9b3361

Ответ 1

Вы можете использовать идиому "rescue nil", чтобы сократить то, что у вас уже есть:

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

Ответ 2

В RSpec 3 вы можете связать два теста с одним. Я считаю, что это более читаемо, чем подход rescue nil.

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

Ответ 3

Вы можете цепочка положительные утверждения с 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)

Вдохновленный этот комментарий.

Ответ 4

Звучит странно, что код 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 status" do
      expect(eating_nothing).to_not change(cat, :status)
    end 
  end
end