RSpec系统测试:工厂创建的关联Order记录无法访问排查
解决方案
1. 检查FactoryBot关联创建逻辑
先确认你的:with_order trait是用create而非build生成关联的Order对象——build只会在内存中生成,不会写入测试数据库,浏览器进程自然拿不到数据。正确的trait写法应该是:
FactoryBot.define do factory :matter do # 这里填matter的基础属性 trait :with_order do after(:create) do |matter| create(:order, matter: matter) # 明确创建并关联order,确保持久化到数据库 end end end end
2. 强制事务提交(针对跨进程数据可见性)
系统测试的浏览器进程和测试进程是独立的,哪怕测试进程里创建了数据,没提交事务的话浏览器进程看不到。可以在测试代码里手动触发提交:
it '访问matter页面并正常显示order ID' do user = create(:user) matter = create(:matter, :with_order, user: user) # 手动提交事务,确保数据写入数据库 ActiveRecord::Base.connection.commit_transaction if ActiveRecord::Base.connection.transaction_open? login_as(user) visit matter_path(matter) expect(page).to have_content(matter.order.id.to_s) end
另外,用create!(带感叹号)替代create,能确保对象创建失败时直接抛出异常,避免静默失败。
3. 控制器预加载关联数据
模板里@order为nil,大概率是控制器没预加载order关联。在MattersController#show方法里,要显式用includes加载关联:
def show @matter = Matter.includes(:order).find(params[:id]) # 或者直接在模板里用@matter.order.id,避免单独赋值@order时的nil风险 end
如果只调用Matter.find,延迟加载关联时可能因为事务隔离问题拿不到数据。
4. 调整数据库隔离级别
部分数据库(比如PostgreSQL)默认隔离级别较高,会导致跨进程看不到未提交数据。可以在系统测试前设置更低的隔离级别:
# spec/rails_helper.rb RSpec.configure do |config| config.before(:each, type: :system) do ActiveRecord::Base.connection.execute("SET TRANSACTION ISOLATION LEVEL READ COMMITTED;") end end
5. 改用DatabaseCleaner管理测试数据
既然已经关闭了use_transactional_fixtures,用DatabaseCleaner的truncation策略替代事务清理,能彻底避免事务隔离问题:
# spec/rails_helper.rb RSpec.configure do |config| config.before(:suite) do DatabaseCleaner.strategy = :truncation DatabaseCleaner.clean_with(:truncation) end config.before(:each, type: :system) do DatabaseCleaner.strategy = :truncation end config.before(:each) do DatabaseCleaner.start end config.after(:each) do DatabaseCleaner.clean end end
Truncation会直接清空表数据,确保每次测试的环境干净,同时创建的数据能立即被浏览器进程读取。
内容的提问来源于stack exchange,提问作者Frexuz
相关产品推荐
相关产品推荐

