简体   繁体   English

如何使用 Rspec 测试控制器中的销毁故障?

[英]How to test destroy failure in controller using Rspec?

I have a books controller with the following action...我有一个具有以下操作的书籍控制器...

def destroy
   @book = Book.find(params[:id])
   if @book.destroy
     redirect_to(books_path)
   else
     render('delete')
   end
 end

I am able to test the the first if case, but not the situation where @book.destroy returns false.我可以测试第一个 if 情况,但不能测试 @book.destroy 返回 false 的情况。 My question is - how do I make @book.destroy fail?我的问题是 - 如何让 @book.destroy 失败? I want to write a rspec test to cover that case.我想编写一个 rspec 测试来涵盖这种情况。

describe "destroy" do
   before(:context) do
     @book = create(:book)
   end
   context "failing the destroy function" do
     it "renders delete" do
       allow(@book).to receive(:destroy).and_return(false)
       delete :destroy, params: { id: @book.id }
       expect(response).to render_template(:delete)
     end
   end
 end

I tried writing the above thinking that allow(@book).to receive(:destroy).and_return(true) would make destroy() return false, but instead, it still returns true and tests the code in the first if statement.我试着写上面的想法,allow(@book).to receive(:destroy).and_return(true) 会使 destroy() 返回 false,但相反,它仍然返回 true 并测试第一个 if 语句中的代码。 I have no idea how to cover the code in the else statement.我不知道如何覆盖 else 语句中的代码。 Any help please?请问有什么帮助吗?

Thanks.谢谢。

The main reason your test does not work is that Book.find will load the record from the database and create a new instance of the class which means that #destroy is not being called on the same object that you have stubbed.您的测试不起作用的主要原因是Book.find将从数据库加载记录并创建该类的新实例,这意味着不会在您存根的同一对象上调用#destroy

You need to stub the Book.find method so that it returns the book instance with the stubbed method:您需要存根Book.find方法,以便它使用存根方法返回 book 实例:

describe "destroy" do
  context "failing the destroy function" do
    let(:book) { build_stubbed(:book) } # use let instead of ivars

    # don't use before :context unless you actually 
    # have a real reason. You should strive to have 
    # each example setup/teardown on their own 
    before do
      allow(book).to receive(:destroy).and_return(false)
      allow(Book).to receive(:find).and_return(book)
    end 

    it "renders delete" do
      delete :destroy, params: { id: book.id }
      expect(response).to render_template(:delete)
    end
  end
end

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM