I have been recently developing Message Queue using Rabbitmq and Sneakers Workers. I had a look on this guide https://github.com/jondot/sneakers/wiki/Testing-Your-Worker
But I still have no idea about how to develop the tests for them. I'm very grateful if there are any advices.
Suggested guide contains Sneakers::Testing
module to store all published messages. In order to do that you need to patch/stub method Sneakers::Publisher#publish
to save published messages into Sneakers::Testing.messages_by_queue
. And then use that data for expectations or somehow supply the data to worker classes.
Probably in most cases you just need inline execution for delayed jobs in specs. So can just patch Sneakers::Publisher#publish
to get worker class by queue name and call its work
method with received payload message. Initial setup:
# file: spec/support/sneakers_publish_inline_patch.rb
# Get list of all sneakers workers in app.
# You can just assign $sneakers_workers to your workers:
#
# $sneakers_workers = [MyWorker1, MyWorker2, MyWorker3]
#
# Or get all classes where included Sneakers::Worker
# Note: can also load all classes with Rails.application.eager_load!
Dir[Rails.root.join('app/workers/**/*.rb')].each { |path| require path }
$sneakers_workers = ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Sneakers::Worker }
# Patch method `publish` to find a worker class by queue and call its method `work`.
module Sneakers
class Publisher
def publish(msg, opts)
queue = opts[:to_queue]
worker_class = $sneakers_workers.find { |w| w.queue_name == queue }
worker_class.new.work(msg)
end
end
end
Or stub method for one worker in a spec:
allow_any_instance_of(Sneakers::Publisher).to receive(:publish) do |_obj, msg, _opts|
MyWorker.new.work(msg)
end
Or add a shared context for convenient way to enable inline jobs execution:
# file: spec/support/shared_contexts/sneakers_publish_inline.rb
shared_context 'sneakers_publish_inline' do
let(:sneakers_worker_classes) do
Dir[Rails.root.join('app/workers/**/*.rb')].each { |f| require f }
ObjectSpace.each_object(Class).select { |c| c.included_modules.include? Sneakers::Worker }
end
before do
allow_any_instance_of(Sneakers::Publisher).to receive(:publish) do |_obj, msg, opts|
queue = opts[:to_queue]
worker_class = sneakers_worker_classes.find { |w| w.queue_name == queue }
raise ArgumentError, "Cannot find Sneakers worker class for queue: #{queue}" unless worker_class
worker_class.new.work(msg)
end
end
end
Then just add include_context 'sneakers_publish_inline'
in spec where you need inline jobs execution.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With