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

在RSpec中为每个测试实现全局可访问的单例Session变量

最优解决方案:依赖注入 + 测试Session封装 + RSpec let 隔离

你的核心痛点是需要在测试用例和API类之间共享一个隔离的、带Cookie管理的Session实例,同时保证每个测试用例的Session独立不污染。下面是一套简洁且可维护的实现方案:

1. 封装TestSession类,统一管理连接与Cookie

首先创建一个专门的测试Session类,把RequestBuilder、Cookie管理、授权信息都封装进去,这样所有API类都可以共享这个实例的状态:

# frozen_string_literal: true
require 'faraday'
require 'faraday/cookie_jar'
require 'framework/util/request'

class TestSession
  attr_reader :conn, :host, :authorization

  def initialize(host, authorization)
    @host = host
    @authorization = authorization
    # 初始化RequestBuilder并启用Cookie自动管理
    @conn = RequestBuilder.new(host)
    @conn.conn.use Faraday::CookieJar # 关键:让Faraday自动处理Set-Cookie和Cookie请求头
  end

  # 可选:添加快捷方法获取当前Cookie,方便调试或特殊场景
  def current_cookies
    @conn.conn.cookies.to_h
  end
end

2. 修改API类,通过依赖注入接收Session

把原来API类中自己初始化RequestBuilder的逻辑去掉,改成接收TestSession实例作为参数,这样所有API类都会共享同一个Session的Cookie状态:

修改后的StudentsApi

require 'framework/util/request'

class StudentsApi
  attr_accessor :session, :user_info, :accounts_register_response

  def initialize(session)
    @session = session
    @user_info = nil
    @accounts_register_response = nil
  end

  def accounts_register(expected_statuses: [201], **options)
    user_hash = {
      first_name: options.fetch(:first_name, nil),
      last_name: options.fetch(:last_name, nil),
      email: options.fetch(:email, nil),
      password: options.fetch(:password, nil),
      remember_me: options.fetch(:remember_me, nil),
      zip_code: options.fetch(:zip_code, nil),
      source: options.fetch(:source, nil)
    }
    headers = {
      'Authorization': session.authorization.auth_string,
      'X-Requested-With': 'XMLHttpRequest',
      'Accept': 'application/json'
    }
    params = { 'user': user_hash}
    @accounts_register_response = session.conn.post(url: '/accounts/register', headers: headers, params: params, expected_statuses: expected_statuses)
    @user_info = User.from_response(@accounts_register_response)
    @user_info
  end

  def accounts_login(email:, password:, accept: 'application/json', **_options)
    headers = {
      'Authorization': session.authorization.auth_string,
      'X-Requested-With': 'XMLHttpRequest',
      'Accept': accept
    }
    params = { 'email': email, 'password': password }
    session.conn.post(url: '/accounts/login', headers: headers, params: params)
  end
end

修改后的CoursesApi

require 'framework/util/request'

class CoursesApi
  attr_accessor :session, :user_info

  def initialize(session)
    @session = session
    @user_info = nil
  end

  def register_course(email:, accept: 'application/json', **_options)
    headers = {
      'Authorization': session.authorization.auth_string,
      'X-Requested-With': 'XMLHttpRequest',
      'Accept': accept
    }
    params = { 'email': email}
    session.conn.post(url: '/register_course', headers: headers, params: params)
  end
end

3. 在RSpec中使用let实现测试隔离

用RSpec的let来定义Session和API实例,let会为每个测试用例生成全新的实例,完美保证测试隔离,同时代码更简洁:

require 'framework/students/api'
require 'framework/courses/api'
require 'framework/test_session'

RSpec.describe 'Creating New Student' do
  # 假设你的授权对象初始化逻辑,根据实际情况调整
  let(:authorization) { Authorization.new('your-api-auth-token') }
  # 每个测试用例都会创建全新的TestSession,彻底隔离状态
  let(:test_session) { TestSession.new('https://your-api-host.com', authorization) }
  let(:new_student) { StudentsApi.new(test_session) }

  it 'allows students to register and login' do
    register_response = new_student.accounts_register(
      first_name: 'John', last_name: 'Doe', 
      email: 'john@example.com', password: 'password123'
    )
    expect(register_response.status).to eq(201)
    
    login_response = new_student.accounts_login(
      email: 'john@example.com', password: 'password123'
    )
    expect(login_response.status).to eq(200)
  end

  it 'allows students to sign up for a course' do
    # 注册并登录后,Cookie会自动存在test_session的CookieJar中
    new_student.accounts_register(
      first_name: 'Jane', last_name: 'Smith', 
      email: 'jane@example.com', password: 'password456'
    )
    new_student.accounts_login(
      email: 'jane@example.com', password: 'password456'
    )

    # 用同一个session初始化CoursesApi,自动共享Cookie
    course_api = CoursesApi.new(test_session)
    course_response = course_api.register_course(email: 'jane@example.com')
    expect(course_response.status).to eq(201)
  end
end

方案优势

  • 完美隔离:每个测试用例的test_session都是全新实例,不会出现跨测试的状态污染
  • 自动共享Cookie:Faraday的CookieJar会自动处理登录返回的Set-Cookie,后续所有请求都会自动带上Cookie
  • 可维护性高:Session逻辑集中在TestSession类,API类只需要专注业务逻辑,后续扩展Session功能(比如添加token刷新、请求日志)只需要修改TestSession
  • 灵活扩展:如果需要在多个测试套件中复用Session逻辑,可以把TestSession和RSpec的let定义抽到共享的spec_helper.rb中

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 18:07:36