【问题标题】:How to test destroy failure in controller using Rspec?如何使用 Rspec 测试控制器中的破坏失败?
【发布时间】:2020-11-07 06:32:22
【问题描述】:

我有一个具有以下操作的图书控制器...

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

我可以测试第一个 if 情况,但不能测试 @book.destroy 返回 false 的情况。我的问题是 - 我如何让 @book.destroy 失败?我想编写一个 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

我尝试编写上述想法,即 allow(@book).to receive(:destroy).and_return(true) 会使 destroy() 返回 false,但它仍然返回 true 并在第一个 if 中测试代码陈述。我不知道如何覆盖 else 语句中的代码。请问有什么帮助吗?

谢谢。

【问题讨论】:

  • 不应该是.and_return(false)

标签: ruby-on-rails rspec


【解决方案1】:

您的测试不起作用的主要原因是Book.find 将从数据库中加载记录并创建该类的新实例,这意味着#destroy 没有在您存根的同一对象上被调用。

您需要存根Book.find 方法,以便它使用存根方法返回图书实例:

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

【讨论】:

  • receive 有错字
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多