Ruby on rails 为控制器中的删除操作编写rspec测试
我的一个控制器中有一个删除功能,如下所示:Ruby on rails 为控制器中的删除操作编写rspec测试,ruby-on-rails,ruby,rspec,factory-bot,Ruby On Rails,Ruby,Rspec,Factory Bot,我的一个控制器中有一个删除功能,如下所示: before_action :set_form, only: [:show, :edit, :update, :destroy] def destroy if @form.destroy render json: @form, status: :ok else render json: @form.errors, status: :not_found end
before_action :set_form, only: [:show, :edit, :update, :destroy]
def destroy
if @form.destroy
render json: @form, status: :ok
else
render json: @form.errors, status: :not_found
end
end
private
def set_form
@form = Form.find(params[:id])
end
end
我有两个问题:
1) 当删除未正确执行时,我返回404。这是合理的身份代码吗?我查看了所有4XX状态代码,这是最有意义的
2) 我不确定如何为呈现json:@form.errors,status::not_found
编写测试
以下是我尝试过的:
context "Cannot delete the model" do
it "responds successfully with an HTTP 404 status code" do
delete :destroy, id: 100000
expect(response).to have_http_status(404)
end
end
问题是,我得到一个错误,说
ActiveRecord::RecordNotFound:找不到'id'=10000的Visa,而不是delete
操作实际失败。如何模拟delete
操作失败?该错误与您在开发甚至生产中会遇到的错误相同。那条线
@form = Form.find(params[:id])
如果未找到带有已传递ID的表单
记录,将引发异常
另外,如果未找到@form
并且您找到了继续的机制,则@form.destroy
仍将不工作,因为nil
对象上没有方法destroy
,而nil
对象上也没有方法错误
如果你坚持按照你描述的方式处理销毁方法,你需要做一些事情,比如
before_action :set_form, only: [:show, :edit, :update] #remove destroy
def destroy
@form = Form.find_by(id: params[:id])
if @form
@form.destroy
render json: @form, status: :ok
else
render json: 'record not found for delete', status: :not_found
end
end
您的set\u form
方法会引发该错误,您必须在那里捕获该错误,或者在destroy
中使用find\u by\u id
def set_form
@form = Form.find(params[:id])
rescue ActiveRecord::RecordNotFound
end
这样,@表单
将在if
中成为nil
关于HTTP状态代码,您可以考虑使用.< /p>
Rails将引发<代码> ActureCordR::当调用“代码>”时,记录NOT/<代码>。在具有无效ID的记录上查找“< /代码>”。这是一个非常理想的行为,因为它在找不到资源时提供了一个很好的捕获。
默认情况下,发送404-notfound头。对于HTML请求类型,它还发送一个默认错误页
相反,问题在于如何测试它
如果要测试rails是否引发错误:
context "Cannot delete the model" do
it "raises an error when the id is not valid" do
bypass_rescue
expect { delete :destroy, id: 100000 }.to raise_error(ActiveRecord::RecordNotFound)
expect(response).to have_http_status(404)
end
end
但是,如果您想测试删除模型是否因任何其他原因(例如记录被锁定或用户未经授权)而失败,则应在数据库中设置一条带有装置或工厂的记录,并提供有效id-还应提供正确的响应代码(422或401)
至于模拟删除失败,您可以使用允许(SomeModel.)的任何实例接收(:destroy)。并返回(false)
是否营救ActiveRecord::RecordNotFound
如果找不到它,只返回@form为nil?这是不是被认为是一种骇客的方式?以前从未遇到过这种情况,因此我很想了解更多关于这种方法的信息。它正在抢救异常,但什么也不做(对于开始抢救结束
块,adef
是隐式的begin
)。实例变量总是初始化为nil
。我只是想告诉你,问题是,你当然也可以在destroy
中进行救援,并将render json:@form.errors,status::not_found
位放在那里。这引发了另一个问题。当destroy
操作失败时,如何进行测试?如何在rspec中模拟此行为以测试呈现json:@form.errors,status::not_found
?而且destroy
函数甚至需要执行错误处理吗?allow(Form).接收(:find).和提高(ActiveRecord::RecordNotFound)
例如:我承认该部分。我真正想问的是如何测试render json:@form.errors,status::not_found
part。当我运行simple cov时,我看到rspec没有涵盖该部分。我想投保,这样我可以100%投保。但我不知道如何测试它,因为我不知道如何使销毁
故意失败。仍然返回ActiveRecord::RecordNotFound
?不,find
将引发,find\u by
将返回nil
。是的,MichaelKohl说了什么。Michael的答案是好的,但您需要准备好在大多数CRUD方法中接收nil对象的可能性:show
,:edit
,:update
,除非您在应用程序控制器中为ActiveRecord::RecordNotFound
添加一个通用的结果。并不是说这是一条路,但我在几个Rails项目中都看到过。是的,我也看到过同样的情况。但他必须再次在所有方法中处理@form
可能是nil
对象的情况。不过,我认为OP还没有准备好调查这种可能性。您介意提供一个额外的测试示例,包括render json:@form.errors,status::not_found
?假设我找到了一个有效的模型。然而,destroy
函数由于某种原因失败,并点击了我写的上面一行。如何在rspec中测试此案例?另外,如果我按照你的样本测试,我会得到200分。我还从您的示例中获得了200
允许(SomeModel.)的任何实例接收(:destroy)。并返回(false)
。如果您能回答我的上述问题,我将不胜感激!