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

Rspec+shared_examples中重复创建对象的原因及解决方法

1. 现象原因

Rspec 中的 let! 会在每个独立测试用例(it 块)执行前触发执行。你这里的 it_behaves_like 本质是把共享示例里的 it 块重复实例化了3次——对应3个产品参数,每个 it 块都是独立的测试用例。因此每个测试用例都会重新执行 let!(:supplier) { create(:supplier) },最终生成3个 supplier 对象。

2. 解决办法

以下两种方案均满足「需要 supplier 的 id、复用测试逻辑」的要求,可根据测试场景选择:

方案一:用 before(:context) 预创建一次 supplier

before(:context) 会在整个 context 块执行前仅运行一次,不受内部测试用例数量影响。如果你的测试不会修改 supplier 对象,这种方式最直接:

before(:context) do
  @supplier = create(:supplier)
end

shared_examples 'a product not in stock with supplier' do |product|
  it 'raises an error' do
    expect { described_class.dispatch_product!(@supplier, product) }.to raise_error 'Product is not in stock'
  end
end

context 'when the state is not supported' do
  it_behaves_like 'a product not in stock with supplier', Chair_1
  it_behaves_like 'a product not in stock with supplier', Table_1
  it_behaves_like 'a product not in stock with supplier', Sofa_1
end

如果担心测试间脏数据影响,可以在 context 末尾添加清理逻辑:

after(:context) do
  Supplier.destroy_all
end

方案二:给 let 加实例变量缓存

利用 Ruby 实例变量的特性手动实现缓存,让 let 仅在第一次调用时创建 supplier:

let(:supplier) do
  @supplier ||= create(:supplier)
end

shared_examples 'a product not in stock with supplier' do |product|
  it 'raises an error' do
    expect { described_class.dispatch_product!(supplier, product) }.to raise_error 'Product is not in stock'
  end
end

context 'when the state is not supported' do
  it_behaves_like 'a product not in stock with supplier', Chair_1
  it_behaves_like 'a product not in stock with supplier', Table_1
  it_behaves_like 'a product not in stock with supplier', Sofa_1
end

注意:这种方式要求所有测试用例都不会修改 supplier 对象,否则会影响后续测试的执行结果。

内容的提问来源于stack exchange,提问作者Quick-gun Morgan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 00:22:17