Ruby on rails 控制器测试中的测试破坏方法

Ruby on rails 控制器测试中的测试破坏方法,ruby-on-rails,rspec,Ruby On Rails,Rspec,我有一个控制器,它可以销毁数据库中的一个项目。现在看起来是这样的: 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.de

我有一个控制器,它可以销毁数据库中的一个项目。现在看起来是这样的:

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
item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)
现在,我已经编写了一些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
?我怀疑这不是真的被打了

更新:

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

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
item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)
更新2:

展开后,您可以设置

current_user.collections.find(params[:collection_id]).items.find_by_id(params[:id])
这是一个很长的通话链。RSpec有办法解决这个问题,但它们在一个名为的部分中说明了这些特性的使用 应视为代码气味

改进代码的一种方法是引入:

这对于存根来说要简单得多,并且有助于将控制器与DB结构解耦<代码>销毁现在可以使用以下代码进行存根:

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

如何在规范中设置
@item
?我怀疑这不是真的被打了

更新:

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

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
item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)
更新2:

展开后,您可以设置

current_user.collections.find(params[:collection_id]).items.find_by_id(params[:id])
这是一个很长的通话链。RSpec有办法解决这个问题,但它们在一个名为的部分中说明了这些特性的使用 应视为代码气味

改进代码的一种方法是引入:

这对于存根来说要简单得多,并且有助于将控制器与DB结构解耦<代码>销毁现在可以使用以下代码进行存根:

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

如何在规范中设置
@item
?我怀疑这不是真的被打了

更新:

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

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
item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)
更新2:

展开后,您可以设置

current_user.collections.find(params[:collection_id]).items.find_by_id(params[:id])
这是一个很长的通话链。RSpec有办法解决这个问题,但它们在一个名为的部分中说明了这些特性的使用 应视为代码气味

改进代码的一种方法是引入:

这对于存根来说要简单得多,并且有助于将控制器与DB结构解耦<代码>销毁现在可以使用以下代码进行存根:

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

如何在规范中设置
@item
?我怀疑这不是真的被打了

更新:

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

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
item = double
allow(Item).to receive(:find).and_return(item)
allow(item).to receive(:destroy).and_return(false)
更新2:

展开后,您可以设置

current_user.collections.find(params[:collection_id]).items.find_by_id(params[:id])
这是一个很长的通话链。RSpec有办法解决这个问题,但它们在一个名为的部分中说明了这些特性的使用 应视为代码气味

改进代码的一种方法是引入:

这对于存根来说要简单得多,并且有助于将控制器与DB结构解耦<代码>销毁现在可以使用以下代码进行存根:

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


为什么毁灭会失败?你们的模型对此有什么验证?公平的问题。没有验证,但是,我可以看到与验证无关的失败原因。也许是打嗝。你基本上是说我应该去掉条件,假设销毁可以工作吗?我仍然想理解为什么我不能取消销毁调用并模拟失败。为什么销毁会失败?你们的模型对此有什么验证?公平的问题。没有验证,但是,我可以看到与验证无关的失败原因。也许是打嗝。你基本上是说我应该去掉条件,假设销毁可以工作吗?我仍然想理解为什么我不能取消销毁调用并模拟失败。为什么销毁会失败?你们的模型对此有什么验证?公平的问题。没有验证,但是,我可以看到与验证无关的失败原因。也许是打嗝。你基本上是说我应该去掉条件,假设销毁可以工作吗?我仍然想理解为什么我不能取消销毁调用并模拟失败。为什么销毁会失败?你们的模型对此有什么验证?公平的问题。没有验证,但是,我可以看到与验证无关的失败原因。也许是打嗝。你基本上是说我应该去掉条件,然后假设销毁会起作用吗?我还是想理解为什么我不能取消销毁调用并模拟失败。我想这就是问题所在。在哪里设置?我是否需要执行以下操作:allow(assigns[:item])接收(:destroy)。和_return(false),因为我尝试了这一操作,但也没有成功。控制器代码发布在上面。还有什么你想看的吗。我试过上面的方法,但也没用。我不熟悉存根和嘲弄,因此非常感谢您的耐心。展示一下
@collection
是如何设置的。我会尝试一下并让您知道,但这里有非常有用的信息。谢谢,谢谢。这一总体概念奏效了。我没有创建服务对象,但是通过在模型中放置逻辑来查找该项,然后按照您的建议将其删除,从而对控制器进行了精简。我想这就是问题所在。在哪里设置?我是否需要执行如下操作:允许(分配[:项])接收(:销毁)和返回(fa)