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

使用Devise/Rspec测试用户登录访问路由时遇before方法报错问题

解决Devise/Rspec控制器测试中login_user宏的错误问题

这个错误的核心原因是你在example内部(it块里)调用了包含before(:each)钩子的宏,而RSpec明确规定before钩子只能在example group(describe/context块)的作用域里定义,不能在单个example里使用。

方案一:修改宏为直接执行登录逻辑

把你的controller_macros里的login_user改成直接执行登录代码,而不是包裹在before(:each)里:

# spec/support/controller_macros.rb
def login_user
  @request.env["devise.mapping"] = Devise.mappings[:user_confirmed]
  @user = FactoryBot.create(:user_confirmed)
  sign_in @user
end

def login_admin
  @request.env["devise.mapping"] = Devise.mappings[:admin]
  @user = FactoryBot.create(:admin)
  sign_in @user
end

然后在测试里,你可以选择在before块里(作用于整个group)或者直接在it块里调用:

require "rails_helper"
RSpec.describe BallotsController, type: :controller do
  describe "index" do
    # 方式1:在before块里调用,作用于当前describe下的所有example
    before do
      login_user
    end

    it "renders successfully" do
      # 注意:控制器测试需要用get方法发起请求,不是直接写ballots_path
      get :index
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end
end

或者直接在单个example里调用:

it "renders successfully" do
  login_user
  get :index
  expect(response).to be_success
  expect(response).to render_template("index")
end

方案二:保持宏的钩子写法,但在group层面调用

如果你想保留宏里的before(:each)逻辑(让它自动作用于整个group的所有example),那你需要在describe/context块里调用login_user,而不是在it块里:

require "rails_helper"
RSpec.describe BallotsController, type: :controller do
  describe "index" do
    # 在describe块里调用,这样before(:each)会应用到当前group下的所有example
    login_user

    it "renders successfully" do
      get :index
      expect(response).to be_success
      expect(response).to render_template("index")
    end
  end
end

额外注意点

你的测试代码里还有一个小问题:ballots_path只是生成路由字符串,不会触发控制器的请求。在RSpec控制器测试中,需要用get :index(或者对应HTTP方法的方法,比如post、put等)来模拟发起请求,这样才能得到response对象进行断言。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:52:34