Benito Serna
Ruby/Rails, TDD, Software...

How to test that an specific email was sent

There are different practices, that I know, to test that an email was sent in Rails…

Althoug I have my preferences, I will try to explain and show you some real examples of how to use these methods, because some teams will prefer one method over the other and is good for you to know the three ways.

Check for the ActionMailer::Base.deliveries

For me the problem with the first approach is that you are mixing you business logic with the mechanisms provided by Rails… And the problem for the second approach is that the API for the rails mailers is a little hard to mock, and also if you try to mock (as a verb) the mailer provided by Rails I think you are not using mocks (as a noun) quite right…

But the good news is that actually you don’t need to use non of this two… you will have one more option =)

The third option… is a little bit different, but may help you in cases like a new change in the rails API, or a change in the way you want to deliver (like use deliver_now instead of deliver_later).

What you can do is to pass a mailer as a dependency to the method that you are testing, but not the mailer from rails… Instead you can pass an object that will do the the things in the “way that you want”…

For example if you want to check that you are sending the right mail after the registration of a user… you could do…

class DummyMailer
  def self.send_welcome_message(user)

it "sends a welcome email" do
  allow(store).to receive(:create).and_return(user)
  expect(mailer).to receive(:send_welcome_message).with(user)
  register_user(params, store, mailer)

And then in the controller where you will be calling that method, you can write the “real” implementation of that mailer…

class RegistrationsController < ApplicationController
  def create
    Registrations.register_user(params[:user], User, Mailer)
    # ...

  class Mailer
    def self.send_welcome_message(user)

In this way you will be testing that you are sending the right message, to the right object, with the right data (arguments).

And then all that you need is to create a very simple object that has no logic, just the responsibility of knowing how ActionMailer wants to be called.

I prefer and recommend this method… because in this way you will have more control over the dependencies that you have. I think this is good example of the “Dependency inversion principle”.

I am not sure if it is your taste, but is another way to solve the problem =).