You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在RSpec请求测试中测试Rails控制器关注点并配置路由?

如何在RSpec请求测试中单独测试控制器关注点?

背景

我们有如下控制器关注点:

module BillingErrorRescuer
  extend ActiveSupport::Concern

  included do
    rescue_from Billing::LimitExceeded, with: :rescue_billing_limits

    def rescue_billing_limits
      render status: 402, json: Billing::PlanPresenter.new(@account).to_json
    end
  end
end

在控制器测试中,我们可以通过匿名控制器单独测试这个关注点:

require 'spec_helper'

describe BillingErrorRescuer, type: :controller do
  controller do
    include BillingErrorRescuer

    def action
      @account = FactoryBot.create :account
      raise Billing::LimitExceeded
    end
  end

  before do
    routes.draw { get :action, to: "anonymous#action" }
    get :action
  end

  let(:account) { create :account, state: :trial }

  it 'renders json with billing data' do
    expect(response.body).to match_json_schema('controllers/billing_error_rescuer')
  end
end

问题

现在需要在RSpec请求测试中实现同样的测试,但尝试配置路由时遇到了404错误。之前试过直接在before块中写routes.draw { get :action, to: "anonymous#action" },也用过around块修改路由,但调用get '/action'时始终返回404。

解决方案

请求测试的上下文与控制器测试不同,不能直接复用匿名控制器的写法,需要显式定义临时控制器并正确配置路由:

require 'spec_helper'

describe BillingErrorRescuer, type: :request do
  # 显式定义临时测试控制器
  class TestBillingController < ApplicationController
    include BillingErrorRescuer

    def action
      @account = FactoryBot.create(:account)
      raise Billing::LimitExceeded
    end
  end

  before do
    # 向Rails全局路由添加临时路由
    Rails.application.routes.draw do
      get '/action', to: 'test_billing#action'
    end
  end

  after do
    # 测试结束后重置路由,避免影响其他测试用例
    Rails.application.routes.reload!
  end

  it '返回包含账单数据的JSON,状态码为402' do
    get '/action'
    
    expect(response).to have_http_status(:payment_required)
    expect(response.body).to match_json_schema('controllers/billing_error_rescuer')
  end
end

关键说明

  1. 不能用匿名控制器:请求测试不支持控制器测试的controller块语法,必须显式定义控制器类(如TestBillingController),确保Rails能找到对应的控制器处理请求。
  2. 操作全局路由:请求测试中需要直接修改Rails.application.routes,而不是控制器测试中的routes对象,否则路由不会生效。
  3. 重置路由:测试完成后必须调用Rails.application.routes.reload!清除临时路由,防止后续测试受到影响。
  4. 使用完整路径:请求时要调用get '/action',而不是符号形式的get :action,符合请求测试的URL调用规范。

内容的提问来源于stack exchange,提问作者Alexander Presber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 07:42:31