RSpec: как правильно смоделировать сбой #destroy

Мне очень трудно имитировать отказ метода уничтожения в моем контроллере.

Уничтожение моего контроллера выглядит так:

def destroy
   project = Project.find(params[:id])
   project.destroy

  if project.destroyed?
    render json: {
      project: nil,
      message: "The project was successfully deleted"
    }
  else
    render json: {
      message: "Could not delete project",
    }, status: :unprocessable_entity
  end
end

Я пытаюсь отобразить json в блоке else в своем тесте, но не могу это сделать. Пока конкретный тест выглядит так:

describe "DELETE #destroy" do

 let!(:project) { create(:project, :open) }

  context "when invalid" do

   it "returns an error if the project was not deleted" do
     expect(Project).to receive(:find).with(project.id.to_s).and_call_original
     expect(project).to receive(:destroy).and_return(false)
     delete :destroy, id: project
   end

 end
end

Тест либо возвращает «счастливый путь», либо выдает мне ошибки. В данный момент:

 Failure/Error: expect(project).to receive(:destroy).and_return(false)

       (#<Project:0x007f87cf5d46a8>).destroy(*(any args))
           expected: 1 time with any arguments
           received: 0 times with any arguments

Если бы кто-нибудь мог указать мне правильное направление и объяснить, как я могу смоделировать 422, я был бы очень благодарен!


person Iris    schedule 23.03.2016    source источник


Ответы (1)


Вы хотите разрешить в начале, а не ожидать. Ожидание — это часть утверждения.

it "returns an error if the project was not deleted" do
  allow(Project).to receive(:find).with(project.id.to_s).and_call_original
  allow(project).to receive(:destroy).and_return(false)

  delete :destroy, id: project

  expect(Project).to have_received(:find)
  expect(project).to have_received(:destroy)
end

Я предполагаю, что вы правы с

allow(Project).to receive(:find).with(project.id.to_s).and_call_original

но я никогда не видел этого раньше, я бы обычно сделал

allow(Project).to receive(:find).with(project.id.to_s).and_return(project)
person j-dexx    schedule 23.03.2016
comment
Спасибо за ваш быстрый ответ! Ожидание (проект). для получения (: уничтожение) выдает ошибку неопределенного метода. Если я распечатаю response.body на консоли, я все равно увижу результат «счастливого пути». Как работает метод allow() и_return(false)? - person Iris; 23.03.2016
comment
Извини, @Iris, это должно быть have_received. По сути, это находится в моках rspec. По сути, это просто говорит rspec, чтобы проект получил вызов destroy и вернул то, что мы хотим, то есть false. Вы захотите добавить другие утверждения, чтобы проверить сообщение/статус. - person j-dexx; 23.03.2016
comment
Спасибо @j-dexx. Прикинул, попробовал, но теперь опять получаю тот самый Failure/Error: expect(project).to have_received(:destroy) (#<Project:0x007f89b4fb4a88>).destroy(*(any args)) expected: 1 time with any arguments received: 0 times with any arguments :( - person Iris; 23.03.2016
comment
Может быть, это потому, что я не использую двойника? - person Iris; 23.03.2016
comment
Что, если вы измените разрешение на allow(Project).to receive(:find).and_return(project). Не имеет значения, что вы используете не двойника, а заводскую девушку-фабрику. Я не думаю, что вам нужно project.destroyed?, вы должны просто уметь делать if project.destroy - person j-dexx; 23.03.2016