使用RSpec 3测试sidekiq perform_in

时间:2014-08-11 14:14:25

标签: ruby rspec sidekiq rspec-sidekiq

RSpec 3和sidekiq 3.2.1。我已经正确设置了sidekiq和rspec-sidekiq。

假设我有一个名为WeatherJob的工作人员,它会将天气状况从sunny更改为rainy

class WeatherJob
  include Sidekiq::Worker

  def perform record_id
    weather = Weather.find record_id

    weather.update status: 'rainy'
  end
end

我像这样使用这个工人:

WeatherJob.perform_in 15.minutes, weather.id

在规范中,我使用Timecop模拟时间:

require 'rails_helper'

describe WeatherJob do
  let(:weather) { create :weather, status: 'sunny' }
  let(:now)     { Time.current }

  it 'enqueue a job' do
    expect {
      WeatherJob.perform_async weather.id
    }.to change(WeatherJob.jobs, :size).by 1
  end

  context '15 mins later' do
    before do
      Timecop.freeze(now) do
        Weather.perform_in 15.minutes, weather.id
      end
    end

    it 'update to rainy' do
      Timecop.freeze(now + 16.minutes) do
        expect(weather.status).to eq 'rainy'
      end
    end
  end
end

我可以看到Weather.jobs数组中有工作。时间恰好是16分钟后。但它没有执行这项工作?有什么建议吗?谢谢!

4 个答案:

答案 0 :(得分:5)

Sidekiq有三种测试模式:已禁用虚假内嵌。默认值为 fake ,它只是将所有作业推送到作业数组中,这是您所看到的行为。 内联模式立即运行作业,而不是将其排入队列。

要强制Sidekiq在测试期间内联运行作业,请将测试代码包装在Sidekiq::Testing.inline!块中:

before do
  Sidekiq::Testing.inline! do
    Timecop.freeze(now) do
      Weather.perform_in 15.minutes, weather.id
    end
  end
end

有关测试Sidekiq的更多信息,请参阅official Testing wiki page

答案 1 :(得分:3)

分两步完成。首先测试作业是否已安排,然后在没有时间延迟的情况下内联执行作业。这是一个例子

it "finishes auction  (async)" do
  auction = FactoryGirl.create(:auction)
  auction.publish!

  expect(AuctionFinishWorker).to have_enqueued_sidekiq_job(auction.id).at(auction.finishes_at)
end

it "finishes auction  (sync)" do
  auction = FactoryGirl.create(:auction)
  auction.publish!

  Sidekiq::Testing.inline! do
    AuctionFinishWorker.perform_async(auction.id)
  end

  auction.reload
  expect(auction).to be_finished
end

have_enqueued_sidekiq_job方法来自rspec-sidekiq gem。他们在develop分支机构正在积极开发。确保你包括它

  gem 'rspec-sidekiq', github: "philostler/rspec-sidekiq", branch: "develop"

答案 2 :(得分:2)

如果您想测试作业是否应该在15分钟后执行,那么您应该将测试用例分成两部分。第一部分,你应该测试它是否插入在15分钟内有效的作业(使用模拟)。第二部分,工作是否已正确执行。

答案 3 :(得分:0)

Weather.drain可能是个问题

require 'rails_helper'

describe WeatherJob do
  let(:weather) { create :weather, status: 'sunny' }
  let(:now)     { Time.current }

  it 'enqueue a job' do
    expect {
      WeatherJob.perform_async weather.id
    }.to change(WeatherJob.jobs, :size).by 1
  end

  context '15 mins later' do
    before do
      Timecop.freeze(now) do
        Weather.perform_in 15.minutes, weather.id
      end
    end

    it 'update to rainy' do
      Timecop.freeze(now + 16.minutes) do
        Weather.drain
        expect(weather.status).to eq 'rainy'
      end
    end
  end
end