繁体   English   中英

在Controller测试中测试销毁方法失败

[英]Testing destroy method failure in Controller test

我有一个控制器,它破坏了我数据库中的一个项目。 当前看起来像这样:

before_filter(:except => :toggle_item_owned_state) do
    @collection = current_user.collections.find(params[:collection_id])
end

def destroy
    @item = @collection.items.find_by_id(params[:id])

    if @item.destroy
        redirect_to collection_items_path(@collection)
    else
        flash.now[:alert] = "There was a problem deleting this item."
        redirect_to root_path
    end
end

现在,我编写了一些rspec控制器测试来验证满意的路径,但是我想测试失败的路径(即@ item.destroy失败时)。 我可以想象,执行此操作的正确方法是使用某种模拟或存根,但我无法提出可行的方法。

我尝试了以下一些变化,但无法正常工作:

        context "delete fails" do
            before(:each) do
                allow(@item).to receive(:destroy).and_return(false)
                delete :destroy, :collection_id => batman_collection.id, :id => item_in_collection.id
            end

            it "will generate a flash error message" do
                expect(flash[:alert]).to eq("There was a problem saving your collection.")
            end
        end

如果有人可以提供有关该操作方法的指导或示例代码,我们将不胜感激。

谢谢

您如何在规范中设置@item 我怀疑它实际上并没有被打断。

更新:

在没有看到您的控制器的情况下,我无法提供确切的代码,但是通常情况是这样的:

item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)

更新2:

展开后,您可以通过以下方式设置item

current_user.collections.find(params[:collection_id]).items.find_by_id(params[:id])

这是一个很长的通话周期。 RSpec有解决此问题的方法,但是在“ 使用遗留代码”一节中它们说应将这些功能的使用视为一种代码味道

改进代码的一种方法是引入服务对象

class FindItem
  def self.call(item_id, collection_id, user)
    user.collections.find(params[:collection_id]).items.find_by_id(item)
  end
end

这对于存根而言更加简单,并且有助于将控制器与数据库结构分离。 现在可以使用以下命令destroy

item = double
allow(FindItem).to receive(:call).and_return(item)
allow(item).to receive(:destroy).and_return(false)

暂无
暂无

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

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