使用sidekiq邮件传递进行Rspec功能测试,如何等待邮件观察者?

时间:2017-08-24 10:00:05

标签: ruby-on-rails rspec capybara sidekiq

当我通过deliver_later发送邮件时,它由sidekiq管理,然后我的注册邮件观察员被触发。

我有一个Capybara测试,用于检查观察者代码内部状态的变化,但是如果在点击后没有立即执行观察者,则会随机失败,并且期望无法正常工作。

示例:

# spec
scenario 'Test that fails randomly' do
  click_link "Go!"
  # MyModel#done is a boolean attribute, so we have #done? method availiable
  expect(MyModel.first.done?).to be true
end

# The controller that manages the Go! link, triggers a mailer.
# After the mailer, this is executed.
# Registered observer
def delivered_mail(mail)
  email = Email.find_by_message_id mail.message_id
  email.user.update_attributes done: true
end

有趣的事实:如果我执行此方案被隔离,测试将始终通过。 如果我完全执行测试套件,测试将以9:1失败:传递或多或少。 _(ツ)_ /¯

尝试将其放入rails_helper:

require 'sidekiq/testing'
RSpec.configure do |config|
  Sidekiq::Testing.inline!
end

还将Sidekiq::Testing.inline!放在scenario区块的第一行......没有。同样有趣的事实。

更新

添加了database_cleaner gem,现在每次都失败。

1 个答案:

答案 0 :(得分:1)

Capybara(click_link等)的行动对他们触发的任何行为一无所知。因此,无法保证在click_link行返回后应用程序将执行的操作,而不是单击链接,浏览器将开始执行该操作触发的任何操作。然后你的测试立即检查'MyModel.first.done?`,而浏览器仍然可以提交请求(这是为什么直接检查功能测试中的数据库记录通常不赞成的一个原因。)

解决方案(最终可以在多个驱动程序中可靠地运行的测试结果是检查页面上的可视更改,指示操作已完成。您还需要正确设置ActiveJob以进行测试,以便您可以确保作业已执行。要执行此操作,您需要include ActiveJob::TestHelper,这可以在您的RSpec配置或个别方案中完成,您需要确保ActiveJob::Base.queue_adapter = :test已设置(可以完成)在config / environment / tests.rb文件中,如果需要)。然后假设您的应用程序在操作完成时在屏幕上显示“邮件已发送!”消息,您将会这样做

include ActiveJob::TestHelper 
ActiveJob::Base.queue_adapater = :test
...
perform_enqueued_jobs do
  click_link "Go!"
  expect(page).to have_text('Mail sent!') # This will wait for the message to appear, which guarantees the action has completed and enqueued the job
end # when this returns any jobs enqueued during the block will have been executed

expect(MyModel.first.done?).to be true