如何期望提高 ActiveRecord::RecordNotFound rspec?
Posted
技术标签:
【中文标题】如何期望提高 ActiveRecord::RecordNotFound rspec?【英文标题】:How to expect raise ActiveRecord::RecordNotFound rspec? 【发布时间】:2022-01-10 16:04:05 【问题描述】:如何获得这个错误的测试通过?
Rspec 控制器和结果
context 'invalid confirmation_token' do
subject do
post signup_step5_path,
params:
user:
password: 'hoge',
password_confirmation: 'hoge',
confirmation_token: 'wrong_token'
end
let(:user) User.find_by(confirmation_token: 'testtesttest')
it 'does not update user attributes and never create an end_point record' do
expect subject .raise_error(ActiveRecord::RecordNotFound)
expected ActiveRecord::RecordNotFound but nothing was raised
控制器方法 我抢救 ActiveRecord::RecordNotFound 并在私有方法中呈现 404 页面。
class Users::SignupController < ApplicationController
layout 'devise'
rescue_from ActiveRecord::RecordNotFound, with: :render404
def step5
@user = User.find_by(confirmation_token: step5_params[:confirmation_token])
raise ActiveRecord::RecordNotFound unless @user
.....
end
private
def render404(error = nil)
logger.info "Rendering 404 with exception: #error.message" if error
render file: Rails.root.join('public/404.ja.html'), status: :not_found
end
end
【问题讨论】:
【参考方案1】:首先解释一下异常匹配器实际上只会匹配未捕获的异常可能是个好主意。那是因为它基本上只是一个救援语句,并在它使调用堆栈冒泡时救援异常,并且它旨在测试一段代码引发了一个由消费者来捕获的异常 - 这是测试 行为。
另一方面,测试代码引发和挽救异常是测试其工作方式。
def foo
raise SomeKindOfError
end
def bar
begin
raise SomeKindOfError
rescue SomeKindOfError
puts "RSpec will never catch me!"
end
end
describe "#foo" do
it "raises an exception" do
expect foo .to raise_exception(SomeKindOfError)
end
end
describe "#bar" do
it "rescues the exception" do
expect bar .to_not raise_exception(SomeKindOfError)
end
end
当您使用 rescue_from
时,它基本上只是使用 around_action 回调来挽救给定异常的语法糖:
class ApplicationController
around_action :handle_errors
private
def handle_errors
begin
yield
rescue SomeKindOfError
do_something
end
end
end
虽然 RSpec 曾一度为控制器规范提供 bypass_rescue
,但 Rails 和 RSpec 团队都非常不鼓励使用控制器规范,您实际上只是在测试实现而不是行为。
相反,您应该测试实际控制器的作用而不是它的作用。
context 'invalid confirmation_token' do
# explicit use of subject is a code smell
before do
post signup_step5_path,
params:
user:
password: 'hoge',
password_confirmation: 'hoge',
confirmation_token: 'wrong_token'
end
let(:user) User.find_by(confirmation_token: 'testtesttest')
it 'does not update the users password' do
expect(user.valid_password?('hoge')).to be_falsy
end
it 'returns a 404 - NOT FOUND' do
expect(response).to have_http_status(:not_found)
end
# using Capybara in a feature spec is a better way to do this.
it 'renders something' do
expect(response.body).to match("Oh Noes!")
end
end
【讨论】:
【参考方案2】:假设它是request spec,则请求将返回 HTTP 404,您可以为此设置期望:
is_expected.to be_not_found
旁注:
@user = User.find_by(confirmation_token: step5_params[:confirmation_token])
raise ActiveRecord::RecordNotFound unless @user
可以简化为:
@user = User.find_by!(confirmation_token: step5_params[:confirmation_token])
【讨论】:
以上是关于如何期望提高 ActiveRecord::RecordNotFound rspec?的主要内容,如果未能解决你的问题,请参考以下文章