Sidekiq: How to test delay on ActionMailer

Created on 21 Feb 2013  路  8Comments  路  Source: mperham/sidekiq

Hi,
Let's say I send an email through Sidekiq like below.

MyMailer.delay.welcome(param1, param2)

Now I want to test (with Rspec) that I am actually queuing an email with specific params. How should I do that with Rspec?

I try to stub_chain'' but it did not work.

Thanks

Most helpful comment

If you use rspec-sidekiq this pull-request might be handy. It lets you write:

          expect(SomeMailer.instance_method :some_mail).to be_delayed(args)

All 8 comments

Did you look in the wiki? :cake:

https://github.com/mperham/sidekiq/wiki/Testing

Thanks but it solves half of the problem.
The Wiki shows how to test if something is queued but for example I cannot test if the first param is eql to '[email protected]' for example.

The job's in the array. Pull it out and introspect it.

Cool! Thanks a lot :)

Related to this:

require 'sidekiq/testing'

Sidekiq::Testing.fake!

class ExampleMailer < ActionMailer::Base
  def example_mail(destination, content)
    puts "Sending an email to #{destination}:\n#{content}"
  end
end

class RegularWorker
  include Sidekiq::Worker

  def perform(destination, content)
    puts "Doing something else with email #{destination}\n#{content}"
  end
end

RegularWorker.perform_async("[email protected]", "Hello world!")
ExampleMailer.delay.example_mail("[email protected]", "Hello world!")
regular_job = RegularWorker.jobs.first
mailer_job = ExampleMailer.jobs.first
puts "args on the first RegularWorker job: #{regular_job["args"]}"
puts "args on the first DelayedMailer job: #{mailer_job["args"]}"

This prints for me:

$ rails runner ./sidekiq_testcase.rb
ran MailTrigger#do_thing
args on the first RegularWorker job: ["[email protected]", "Hello world!"]
args on the first DelayedMailer job: ["---\n- !ruby/class 'ExampleMailer'\n- :example_mail\n- - [email protected]\n  - Hello world!\n"]

I think I understand why this happens: DelayedMailer jobs still have to be dispatched to the right ActionMailer class and method so there's another layer of indirection in the job arguments. So to get the args out I actually had to do another step:

(target, method_name, args) = YAML.load(mailer_job["args"].first)

I think it would be more convenient (but maybe unnecessary or even intrusive) if Sidekiq's fake testing mode dispatched mailer jobs onto arrays specific to the class/method_name, something like ExampleMailer.sidekiq_jobs.example_mail or somewhere on Sidekiq::Extensions::DelayedMailer, so that we could check jobs for a specific mailer and method directly. It feels wrong to have to rely on an implementation detail of DelayedMailer to test the args passed to delayed mailer jobs.

If you use rspec-sidekiq this pull-request might be handy. It lets you write:

          expect(SomeMailer.instance_method :some_mail).to be_delayed(args)

Hey @mperham , it seems like none of these solutions work on Rails 5.2 for mailers based on ActiveJob and without Delayed extensions. Do you recommend using Delayed extensions for delayed emails, or is it better to stick deliver_later?

@FunkyloverOne assuming deliver_later:

```ruby
class SomeControllerTest < ActionDispatch::IntegrationTest
include ActiveJob::TestHelper

test "enque an email" do
assert_enqueued_with queue: "mailers" do
post some_path
end
end
end

Was this page helpful?
0 / 5 - 0 ratings

Related issues

homanchou picture homanchou  路  3Comments

aglushkov picture aglushkov  路  3Comments

mperham picture mperham  路  4Comments

HenleyChiu picture HenleyChiu  路  4Comments

davidcelis picture davidcelis  路  3Comments