在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
相关产品推荐
相关产品推荐

