如何期望引发ActiveRecord::RecordNotFound rspec



如何获得此错误的测试通过?

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

首先,解释异常匹配器实际上只匹配未捕获的异常可能是个好主意。这是因为它基本上只是一个救援语句,并在调用堆栈中弹出时救援异常,它旨在测试一段代码是否引发了一个由消费者捕获的异常——这是测试行为的一个例子。

另一方面,测试代码引发和挽救异常就是测试它是如何完成任务的。

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

假设这是一个请求规范,请求将返回HTTP404,您可以为此设置一个期望值:

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])

最新更新