Johan Sørensen

On ActionMailer fixtures

I see posts like this and the way that Rails’ ActionMailer generator does test fixtures by default and I simply wonder to myself why bother?

Personally I find it extremely painful having to maintain a piece of template fixture; every time I change the wording or fix a spelling error in the mailer template I have to update the fixture.
Testing purists might say that’s the way it should be, but for me it makes me loose respect for my tests, I simply just update the fixture without thinking too much what was wrong since I’m generally lazy.

But I prefer being a different kind of lazy, so instead I check that my ActionMailer templates simply contains the important bits that I expect them to contain. Like a registration key, or a username and password or a certain sentence (I believe it was my coworker Koz that showed me this in a commit once). Not unlike how you’d do functional tests; making sure that the important elements/objects are in the rendered template, instead of comparing the entire rendered template to a fixture (which I believe pretty much no-one does).

So, instead of comparing the entire #body of the ActionMailer TMail object to the fixture I usually just do something like this:

def setup
  @user = users(:myfixtureuser)
  ActionMailer::Base.deliveries = []

def test_welcome_mail
  assert !ActionMailer::Base.deliveries.empty?

  sent = ActionMailer::Base.deliveries.first
  assert_equal [],
  assert_equal "expected subject", sent.subject
  assert sent.body =~ /^Welcome to my App/
  assert sent.body =~ /^Username: #{@user.login}$/
  assert sent.body =~ /^Password: [a-z0-9]{10}$/i

So that makes sure the email was sent, that the recipent and subject are correct, that the template rendered looks like the one we expected and finally that it contains the information needed for the user to login. All without the boring chores of maintaining static fixtures.

Update: I was flipping through the Agile Webdev with Rails book today, and what do I see on page 420-421? The very same approach, even with the same arguments, so that must be where I got it from to begin with…


  1. Nathaniel Talbott Says:

    I just did this recently as well – excellent tip!

    FYI, if you use assert_match you’ll get better failure reporting, i.e.:

    assert_match(/^Welcome to my App/, sent.body)

  2. johan Says:

    yeah, for some reason I tend to stick with assert_equal() and assert() for most things, even when one of the other assert_* might be a better choice.

  3. Shanti Says:

    I, too, saw that approach… only after I had extracted all my ActionMailer fixtures.

    In the future, I’ll def. be doing it that way instead.