如何获得此错误的测试通过?
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])