Rspec sidekiq邮件投递功能测试,如何等待邮件观察者?
Rspec feature test with sidekiq mail delivery, how to wait for mail observer?
当我通过 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 fail:pass。 ¯_(ツ)_/¯
尝试将其放入 rails_helper:
require 'sidekiq/testing'
RSpec.configure do |config|
Sidekiq::Testing.inline!
end
并且还将 Sidekiq::Testing.inline!
放在 scenario
块的第一行......什么都没有。同样有趣的事实。
更新:
添加了database_cleaner
gem,现在每次都失败。
Capybara 中的动作(click_link
,等等)对它们触发的任何行为一无所知。因此,无法保证在您的 click_link
行 returns 之后应用程序将执行的操作,除了 link 将被单击,并且浏览器将开始执行无论该动作触发什么。然后,您的测试会立即检查“MyModel.first.done?”,而浏览器可能仍在提交请求(这就是为什么在功能测试中直接检查数据库记录通常不受欢迎的原因之一)。
对此的解决方案(并以可靠地跨多个驱动程序的测试结束)是检查页面上是否有视觉变化,指示操作已完成。您还需要正确设置 ActiveJob 以进行测试,以便您可以确保作业已执行。为此,您需要 include ActiveJob::TestHelper
,这可以在您的 RSpec 配置或个别场景中完成,并且您需要确保 ActiveJob::Base.queue_adapter = :test
已设置(如果需要,可以在 config/environment/tests.rb 文件中完成)。然后假设您的应用在操作完成后在屏幕上显示一条消息 "Mail sent!",您将执行
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
当我通过 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 fail:pass。 ¯_(ツ)_/¯
尝试将其放入 rails_helper:
require 'sidekiq/testing'
RSpec.configure do |config|
Sidekiq::Testing.inline!
end
并且还将 Sidekiq::Testing.inline!
放在 scenario
块的第一行......什么都没有。同样有趣的事实。
更新:
添加了database_cleaner
gem,现在每次都失败。
Capybara 中的动作(click_link
,等等)对它们触发的任何行为一无所知。因此,无法保证在您的 click_link
行 returns 之后应用程序将执行的操作,除了 link 将被单击,并且浏览器将开始执行无论该动作触发什么。然后,您的测试会立即检查“MyModel.first.done?”,而浏览器可能仍在提交请求(这就是为什么在功能测试中直接检查数据库记录通常不受欢迎的原因之一)。
对此的解决方案(并以可靠地跨多个驱动程序的测试结束)是检查页面上是否有视觉变化,指示操作已完成。您还需要正确设置 ActiveJob 以进行测试,以便您可以确保作业已执行。为此,您需要 include ActiveJob::TestHelper
,这可以在您的 RSpec 配置或个别场景中完成,并且您需要确保 ActiveJob::Base.queue_adapter = :test
已设置(如果需要,可以在 config/environment/tests.rb 文件中完成)。然后假设您的应用在操作完成后在屏幕上显示一条消息 "Mail sent!",您将执行
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