如何期望提高 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?的主要内容,如果未能解决你的问题,请参考以下文章

2021.7.15提高B组模拟4T1 彩色圆环(期望dp)

如何设定目标,避免推理阶梯(素材)

2021.8.12提高B组模拟4T1 幻象(期望dp)

《对软件工程课程的期望》

2021.8.12提高B组模拟4T1 幻象(期望dp)

NOIP2016提高组换教室