Rails 7下如何在Rspec中创建对象前正确设置租户?
问题根源
let是惰性求值特性,仅在第一次被调用时执行代码。虽然顶级before块会在每个测试用例前设置租户,但如果租户设置的作用域未覆盖到customer创建时机,或者多租户实现要求操作必须包裹在特定上下文内,就会触发InvalidTenantAccess错误。
调整方案
方案1:用around块包裹测试上下文
确保整个测试用例都在租户上下文中执行,同时完成清理避免测试污染:
require "rails_helper" RSpec.describe Store, type: :model do around(:example) do |example| # 创建租户并设置上下文 tenant = FactoryBot.create(:tenant) Tenant.set_current_tenant(tenant) # 执行测试逻辑 example.run # 清理租户上下文 Tenant.unset_current_tenant end describe "associations" do let(:customer) { FactoryBot.create(:customer) } it "关联当前租户" do expect(customer.tenant_id).to eq(Tenant.current_tenant.id) end end end
如果使用Apartment这类主流多租户gem,建议用官方switch方法包裹:
around(:example) do |example| tenant = FactoryBot.create(:tenant) Apartment::Tenant.switch(tenant.subdomain) do example.run end end
方案2:在let中显式绑定租户
针对特定测试用例,直接在customer的let定义中确保租户生效:
require "rails_helper" RSpec.describe Store, type: :model do let(:tenant) { FactoryBot.create(:tenant) } let(:customer) do Tenant.set_current_tenant(tenant) FactoryBot.create(:customer, tenant: tenant) # 显式关联租户更稳妥 end describe "associations" do it "关联正确的租户" do expect(customer.tenant).to eq(tenant) end end end
方案3:修改FactoryBot工厂自动关联租户
调整customer工厂,让它自动绑定当前租户,减少测试代码重复:
# spec/factories/customers.rb FactoryBot.define do factory :customer do tenant { Tenant.current_tenant } # 其他属性定义... end end
测试代码中只需确保租户提前设置:
require "rails_helper" RSpec.describe Store, type: :model do before(:each) do tenant = FactoryBot.create(:tenant) Tenant.set_current_tenant(tenant) end describe "associations" do let(:customer) { FactoryBot.create(:customer) } it "自动继承当前租户" do expect(customer.tenant).to eq(Tenant.current_tenant) end end end
注意:避免使用before(:all),它会导致租户仅创建一次,引发跨测试用例的数据污染,优先用before(:each)或around块。
内容的提问来源于stack exchange,提问作者phil
相关产品推荐
相关产品推荐

