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

Rails集成测试重定向后Session无法访问的问题

Rails集成测试中OmniAuth登录后Session不持久化的问题

问题场景

使用Rails IntegrationTest测试登录用户行为,通过OmniAuth Identity策略实现登录流程:

  • 登录请求由SessionsController#create处理,成功后设置session[:user_id]并重定向到首页
  • 首页WelcomeController#show根据current_user状态显示"Logged In"或"Logged Out"
  • 测试中登录请求执行后,Session在后续请求中丢失,始终显示未登录

相关代码

控制器代码

# Highly simplified logic for the login handler
class SessionsController < ApplicationController
  def create
    auth_hash = request.env['omniauth.auth']
    user = User.find_with_omniauth(auth_hash)
    session[:user_id] = user.id
    Rails.logger.debug(session.inspect)
    redirect_to root_path
  end 
end

class WelcomeController < ApplicationController
  def show
    Rails.logger.debug(session.inspect)
  end
end

class ApplicationController < ActionController::Base
  def current_user
    @current_user ||= if session.key?(:user_id)
                        User.find_by(id: session[:user_id])
                      else
                        nil
                      end
  end
  
  def logged_in?
    current_user.present?
  end
end

测试代码

require 'test_helper'

class WelcomeControllerTest < ActionDispatch::IntegrationTest
  include FactoryBot::Syntax::Methods

  setup do
    OmniAuth.config.test_mode = true
  end

  teardown do
    OmniAuth.config.test_mode = false
    OmniAuth.config.mock_auth[:identity] = nil
  end

  def manual_identity_log_in(user_with_identity)
    OmniAuth.config.mock_auth[:identity] =  OmniAuth::AuthHash.new(
      {
        provider: 'identity',
        uid: user_with_identity.id,
        info: {
          email: user_with_identity.email,
          first_name: user_with_identity.first_name,
          last_name: user_with_identity.last_name,
          name: user_with_identity.full_name
        }
      })

    post '/auth/identity/callback', params: {email: user_with_identity.email, password: ''}
  end

  test "can see the landing page for logged out users" do
    get "/"
    assert_select( "h1", "Logged Out")
  end

  test "can see the welcome page for logged in users" do
    current_user = create(:user_with_identity)
    manual_identity_log_in(current_user)
    get "/"
    assert_select( "h1", "Logged In")
  end
end

解决方法

1. 跟随登录后的重定向

集成测试中,post请求默认不会自动跟随重定向,导致Session未被测试会话捕获。修改登录方法,添加follow_redirect!:

def manual_identity_log_in(user_with_identity)
  OmniAuth.config.mock_auth[:identity] =  OmniAuth::AuthHash.new(
    {
      provider: 'identity',
      uid: user_with_identity.id,
      info: {
        email: user_with_identity.email,
        first_name: user_with_identity.first_name,
        last_name: user_with_identity.last_name,
        name: user_with_identity.full_name
      }
    })

  post '/auth/identity/callback', params: {email: user_with_identity.email, password: ''}
  follow_redirect! # 确保测试会话获取到登录后的Session
end

2. 确认测试环境Session存储配置

检查config/environments/test.rb,确保使用Cookie存储Session(默认配置),避免使用无法跨请求持久化的存储方式:

Rails.application.configure do
  # ... 其他配置
  config.session_store :cookie_store, key: '_your_app_session'
end

3. 验证登录请求的正确性

在测试中添加断言,确认登录请求执行成功,避免因请求失败导致Session未设置:

test "can see the welcome page for logged in users" do
  current_user = create(:user_with_identity)
  manual_identity_log_in(current_user)
  assert_response :success # 验证登录流程无错误
  get "/"
  assert_select( "h1", "Logged In")
end

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:20:30