Use a custom job adapter in test

So you have decided to jump on board the ship to scalability with the custom job adapter from the previous post? Want to use this adapter in your tests? Do you use assert_enqueued_jobs in your tests? If yes, you wouldn’t see duplicate jobs being ignored from the queue. This is because it automatically sets the adapter to test_adapter irrespective of what you have in your test.rb. Not all is lost though. There is a way to use your custom adapter in tests by extending the ActiveJob::TestHelper.

# Specifies the queue adapter to use with all active job test helpers.
#
# Returns an instance of the queue adapter and defaults to
# <tt>ActiveJob::QueueAdapters::TestAdapter</tt>.
#
# Note: The adapter provided by this method must provide some additional
# methods from those expected of a standard <tt>ActiveJob::QueueAdapter</tt>
# in order to be used with the active job test helpers. Refer to
# <tt>ActiveJob::QueueAdapters::TestAdapter</tt>.
def queue_adapter_for_test
  ActiveJob::QueueAdapters::TestAdapter.new
end

Great. All we need is this piece of code in our test_helper and we should be good:

module ActiveJob::TestHelper
  def queue_adapter_for_test
    ActiveJob::QueueAdapters::UniqDelayedJobTestAdapter.new
  end
end

Not so fast, eh! Check out the docs:

Note: The adapter provided by this method must provide some additional methods from those expected of a standard ActiveJob::QueueAdapter in order to be used with the active job test helpers.

OK. A little more digging, and we can extend our adapter to support the methods that the test adapter requires

class ActiveJob::QueueAdapters::UniqDelayedJobTestAdapter < ActiveJob::QueueAdapters::UniqDelayedJobAdapter
  def enqueued_jobs
    Delayed::Job.all.to_a
  end

  def performed_jobs
    []
  end
end

Nice! Run the tests! Still failing… Looks like it expects the elements returned from enqueued_jobs to support a fetch method.

class Delayed::Backend::ActiveRecord::Job
  def fetch(key, default = nil)
    case key
    when :job
      return self.payload_object.job_data["job_class"] || default
    when :queue
      return self.queue || default
    else
      raise "cannot fetch #{key}. Not yet implemented"
    end
  end
end

Finally, we can use the adapter in tests. Don’t forget to update your expected job counts to account for the duplicate ones discarded by the new adapter!

Published 17 Sep 2018

I build mobile and web applications. Full Stack, Rails, React, Typescript, Kotlin, Swift
Pulkit Goyal on Twitter