Rails中用RSpec测试含Sidekiq Batch的Job:batch为nil错误排查
问题根源
报错undefined method 'jobs' for nil:NilClass是因为测试环境中没有模拟Sidekiq Batch的上下文:
- 实际运行时,
AnotherWorker是在ParentWorker的batch.jobs块里被调用的,Sidekiq会自动将当前Batch实例注入到子Job的执行环境中,所以batch变量能直接使用。 - 但测试时是直接调用
AnotherWorker.perform,没有触发Sidekiq的Batch上下文注入,导致batch为nil。
修正后的测试代码
describe AnotherWorker, type: :job do describe '#perform' do subject { described_class.new.perform(asset_id) } let(:asset_id) { create(:asset).id } let(:batch) { instance_double(Sidekiq::Batch) } before do # 模拟Sidekiq Batch的当前上下文,让AnotherWorker能拿到batch实例 allow(Sidekiq::Batch).to receive(:current).and_return(batch) # 模拟batch.jobs块的执行逻辑 allow(batch).to receive(:jobs).and_yield end it 'enqueues ThirdJobWorker 3 times' do subject # 注意:原业务代码中ThirdJobWorker.perform_async未传asset_id,需与实际逻辑匹配 expect(ThirdJobWorker).to have_enqueued_sidekiq_job.exactly(3).times end end end
关键修正点
- 用
allow(Sidekiq::Batch).to receive(:current).and_return(batch)模拟Sidekiq Batch的当前上下文,让AnotherWorker中的batch变量指向mock实例。 - 修正
ThirdJobWorker的入参期望:原业务代码里ThirdJobWorker.perform_async没有传递asset_id,测试需与实际逻辑一致,否则会断言失败。 - 移除重复的
expect(batch).to receive(:jobs).and_yield,避免因重复定义mock导致的期望不匹配。
额外说明
如果需要测试ParentWorker与AnotherWorker的联动逻辑(比如验证ParentWorker触发后,AnotherWorker是否正确入队到Batch中),可单独编写测试用例,模拟Team和Asset的关联关系,验证入队行为。
内容的提问来源于stack exchange,提问作者Anastasiia
相关产品推荐
相关产品推荐

