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

