使用 capybara-webkit 的 Sidekiq 工作行为不稳定

Rom*_*man 5 capybara capybara-webkit sidekiq selenium-webdriver ruby-on-rails-4

我正在维护一套功能规范,其中包含许多在测试中运行的 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
Run Code Online (Sandbox Code Playgroud)

我尝试sleep nexpect语句之间放置- 即使使用n = 10. 然后我尝试调试,并注意到一些奇怪的事情:ImportWorker.jobs返回仍在队列中的作业,如果我ImportWorker.drain从调试器中明确声明,规范将通过。

但!如果我放在ImportWorker.drainexpect行之间- 它仍然失败,即使我sleep在排空之前放置,等待请求实际调用perform_async工人。

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

现在,我有一些深入了解从水豚提出的要求,从规格不同的线程中进行处理,如解释在这里。所以很可能,当 worker 被调用时,它不知道inline!,而只是将作业放入 Redis 队列。我仍然不明白为什么 Selenium 能够管理这个问题。如果这是真的,我如何使用 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
Run Code Online (Sandbox Code Playgroud)

显然,这与最佳实践相距甚远,因此我正在考虑编写一个类,该类将接受工作人员姓名作为字符串或符号,并inline!根据 env使用或不使用块调用 perform 。这样我就可以将这种丑陋保留在一个地方,而无需污染控制器和模型。

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

Tho*_*ole 5

所有 Sidekiq::Testing.inline!do(当传递块时)在执行块之前设置全局(非线程特定)设置,然后在块完成时重置该设置。我相信您的测试失败的原因是,即使您单击块内的按钮/链接,在设置全局内联设置时,作业实际上并未添加到队列中。这是因为#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
Run Code Online (Sandbox Code Playgroud)

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

RSpec.configure do |config|
 config.around(:example, :sidekiq_inline) do |example|
   Sidekiq::Testing.inline! do
     example.run
   end
  end
end   
Run Code Online (Sandbox Code Playgroud)

然后应该让你做

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
Run Code Online (Sandbox Code Playgroud)

你也可以添加一些东西,比如清除 sidekiq 队列到 around 块。