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

无需Devise,如何在测试中创建current_user?

问题描述

我的应用在全局设置了current_user,此前运行正常,但编写测试时出现401未授权错误。

主控制器核心代码:

class ApplicationController < ActionController::API
  ...

  def authenticate_action

  end
end

测试代码:

RSpec.describe 'Api::V1::Articles', type: :request do
  let(:user) { FactoryBot.build_stubbed :user }
  
  describe 'POST /create' do
    context "with valid user params" do
      let!(:articles_params) { {article:{ name: "art1" } }}
      it 'creates a new article' do
        expect { post "/api/v1/posts/1/articles", params: articles_params }  .to change(Article, :count).by(1)
      end
    end
  end
end

错误信息:

Completed 400 Unauthorized
解决方法

核心问题是测试请求没通过authenticate_action的认证校验,需要在测试中模拟用户的认证状态,以下是几种常用方案:

方案1:模拟token认证(最常用)

如果你的authenticate_action是通过请求头携带token验证用户,直接在测试请求里添加认证头即可:

it 'creates a new article' do
  # 生成符合你系统规则的认证token,比如从用户模型获取
  auth_token = user.auth_token
  expect { 
    post "/api/v1/posts/1/articles", 
         params: articles_params,
         headers: { 'Authorization' => "Bearer #{auth_token}" }
  }.to change(Article, :count).by(1)
end

方案2:临时绕过认证(仅用于特定场景)

如果只是想快速验证接口逻辑,可临时存根认证方法跳过校验:

before do
  allow_any_instance_of(ApplicationController).to receive(:authenticate_action).and_return(true)
end

it 'creates a new article' do
  expect { post "/api/v1/posts/1/articles", params: articles_params }  .to change(Article, :count).by(1)
end

方案3:使用项目封装的登录辅助方法

如果项目里有现成的登录辅助方法(比如login_as),直接调用即可:

before do
  login_as(user) # 调用项目内设置current_user的辅助方法
end

it 'creates a new article' do
  expect { post "/api/v1/posts/1/articles", params: articles_params }  .to change(Article, :count).by(1)
end

额外注意点

  • 若build_stubbed创建的用户未持久化到数据库,而认证逻辑需要查询数据库,建议改用create生成真实用户:
    let(:user) { FactoryBot.create :user }
    
  • 确认请求路径中的posts/1对应的Post记录存在,否则会引发额外错误,可提前创建:
    let(:post) { FactoryBot.create :post }
    it 'creates a new article' do
      expect { 
        post "/api/v1/posts/#{post.id}/articles", 
             params: articles_params,
             headers: { 'Authorization' => "Bearer #{user.auth_token}" }
      }.to change(Article, :count).by(1)
    end
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 06:45:32