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

如何在Rspec中Stub JWT认证逻辑里的current_user?

如何在Rails控制器测试中绕过JWT认证并设置@current_user

你遇到的核心问题是:测试中@current_user始终为nil,因为你之前的Stub方式只是让authorize方法返回用户对象,并没有在控制器实例中实际设置@current_user变量,而控制器的create方法依赖这个实例变量完成逻辑。

以下是几种可行的解决方案:

方案1:跳过认证前置动作并直接设置@current_user

这是最直接的方式,完全绕过authorize的执行,直接给控制器实例注入@current_user:

require 'rails_helper'
RSpec.describe BooksController do
  let(:current_user) { User.create(username: "Joe") }
  
  before :each do
    # 跳过authorize前置验证动作
    controller.skip_before_action :authorize
    # 给控制器实例设置@current_user变量
    controller.instance_variable_set(:@current_user, current_user)
  end

  context 'book creation' do
    it 'authenticated user can create book' do
      post :create, params: { book: { name: "Some Book" } }
      expect(response).to have_http_status(:created)
    end
  end
end

方案2:Stub authorize方法让它设置@current_user

如果你不想完全跳过authorize方法,可以Stub它的执行逻辑,让它直接完成@current_user的设置:

require 'rails_helper'
RSpec.describe BooksController do
  let(:current_user) { User.create(username: "Joe") }
  
  before :each do
    allow(controller).to receive(:authorize) do
      # 在Stub的authorize方法中设置@current_user
      controller.instance_variable_set(:@current_user, current_user)
    end
  end

  context 'book creation' do
    it 'authenticated user can create book' do
      post :create, params: { book: { name: "Some Book" } }
      expect(response).to have_http_status(:created)
    end
  end
end

方案3:Stub第三方JWT验证逻辑(保留authorize执行)

如果你希望保留authorize方法的完整执行流程,只是绕过第三方API调用,可以模拟验证响应结果:

require 'rails_helper'
RSpec.describe BooksController do
  let(:current_user) { User.create(username: "Joe") }
  
  before :each do
    # 模拟第三方验证的响应结果,包含对应用户ID
    mock_validation_response = double(
      decoded_token: [[{ "sub" => current_user.id }]],
      error: nil
    )
    # Stub客户端的验证方法,返回模拟结果
    allow_any_instance_of(Secured).to receive(:client).and_return(
      double(verify_token_from_third_party: mock_validation_response)
    )
  end

  context 'book creation' do
    it 'authenticated user can create book' do
      post :create, params: { book: { name: "Some Book" } }
      expect(response).to have_http_status(:created)
    end
  end
end

额外需要修正的代码问题

除了测试代码,你的控制器代码存在两处拼写错误,会导致测试失败:

  1. 控制器类名错误:BookssController 应改为 BooksController
  2. 实例变量名不一致:create方法中初始化的是@books,后续却用@book调用save,需统一为@book:
# 修正后的create方法
def create
  @book = Book.new(book_params.merge({user_id: @current_user.id}))

  if @book.save
    render json: @book, status: :created, location: @book
  else
    render json: @book.errors, status: :unprocessable_entity
  end
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 15:47:36