使用水豚网络套件的不稳定的 Sidekiq 作业行为



我正在维护一套功能规范,其中许多 sidekiq 作业在测试中运行。一切都很好,直到需要为所有功能规范启用javascript,事情突然变得丑陋。我不确定我是否理解其中的原因。

一个典型的问题如下所示:在规范开始时,我调用了助手,最终启动了 Sidekiq 作业:

it 'does something fancy' do
  Sidekiq::Testing.inline! do
    page.attach_file('black_list_file', file)
    click_on 'Import file'
  end
  expect(page).to have_content('Import started') # No problem here
  expect(page).to have_link('imported_file.csv') # This fails
end

我试图在expect陈述之间放sleep n - 即使有n = 10也没有运气.然后我尝试调试,并注意到一些奇怪的事情:ImportWorker.jobs返回仍在队列中的作业,如果我从调试器显式声明ImportWorker.drain,规范将通过。

但!如果我ImportWorker.drain放在expect行之间 - 即使我把sleep放在 drain 之前,它仍然无法等待请求在 worker 上实际调用perform_async

当我切换到硒驱动程序时,事情变得更加奇怪 - 一切都很顺利,测试通过。

现在,我对如何处理从水豚发出的请求在与规范不同的线程中处理有一些见解,如此处所述。所以很可能,当调用 worker 时,它不知道inline!,只是将作业放入 Redis 队列。我仍然不明白为什么硒能够解决这个问题。如果这是真的,我如何使用webkit驱动程序测试涉及sidekiq作业的功能。

上。

好的,正如我所期望的那样,Sidekiq::Testing.inline?在调用 worker 的地方返回 false,即使请求是从inline!块发出的。

这解决了所有问题:

if Rails.env.test?
  Sidekiq::Testing.inline! do
    ImportWorker.perform_async(args)
  end
else
  ImportWorker.perform_async(args)
end

显然,这与最佳实践相去甚远,所以我正在考虑编写一个类,该类将接受工人名称作为字符串或符号,并根据 env 调用带有或不带有inline!块的 perform。这样我就可以把这种丑陋的东西放在一个地方,而不需要污染控制器和模型。

如果您认为这是一个糟糕的解决方案,请发表评论。

all sidekiq::Testing.inline! 在执行块之前设置全局(不是特定于线程的)设置,然后在块完成时重置该设置。 我相信您的测试失败的原因是,即使您单击块内的按钮/链接,在设置全局内联设置时,作业实际上也没有添加到队列中。 这是因为#click_on单击后立即返回,并且不需要等待该单击的任何副作用发生(表单提交,JS行为等)。 如果你把你的期望(等待副作用发生)移到块内,那么测试应该通过。

it 'does something fancy' do
  Sidekiq::Testing.inline! do
    page.attach_file('black_list_file', file)
    click_on 'Import file'
    expect(page).to have_content('Import started') # No problem here
    expect(page).to have_link('imported_file.csv') 
  end
end

另一种选择是根据测试中设置的元数据在块周围使用 RSpec 更改 Sidekiq 测试设置 - 将类似以下内容的内容添加到您的 RSpec 配置中(注意:未尝试)

RSpec.configure do |config|
 config.around(:example, :sidekiq_inline) do |example|
   Sidekiq::Testing.inline! do
     example.run
   end
  end
end   

然后应该让你做

it 'does something fancy', :sidekiq_inline do
  page.attach_file('black_list_file', file)
  click_on 'Import file'
  expect(page).to have_content('Import started') # No problem here
  expect(page).to have_link('imported_file.csv') 
end

您还可以添加诸如清除 sidekiq 队列之类的内容到周围的块中。

最新更新