5

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

假设我有一个名为 的工人WeatherJob,它将天气状态从更改sunnyrainy

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

4 回答 4

5

Sidekiq 具有三种测试模式:disabledfakeinline。默认值为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 的更多信息,请参阅官方测试 wiki 页面

于 2014-08-11T20:47:47.113 回答
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"
于 2017-02-13T13:24:46.640 回答
2

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

于 2014-12-23T15:00:45.687 回答
1

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
于 2020-05-06T08:24:42.240 回答