Saturday, November 24, 2007

testing mailers in rails

AFAIK, the only way to test mailers is to create a mail object directly, and then look for textual matches within the mail body.
That's lame. I wanted something more akin to the 'template_objects' method that you can call on a response when writing functional tests.

Turns out that ActionMailer::Base does some funky stuff that makes it really hard to do this. Here's what I resorted to in the mean time:

Let's say that my NotificationMailer looks something like:

class NotificationMailer < ActionMailer::Base
def my_notification_method
@body['name'] = "bob"
end
end


add the following code in test_helper.rb:

ActionMailer::Base.class_eval {
alias initialize_which_results_in_auto_create initialize
def initialize( method_name = nil, *params )
return if( :test == method_name )
initialize_which_results_in_auto_create( method_name, *params )
end

class << ActionMailer::Base
def grab_vars( method, *params )
obj = new(:test)
obj.send( :initialize_defaults, method )
obj.send( method, *params )
return {:body => obj.body, :subject => obj.subject, :recipients => obj.recipients}
end
end # class
}


I can now check for 'assigns' as follows:

nm = NotificationMailer.grab_vars( :my_notification_method )
assert_equal( "bob", nm[:body]['name'] )


That's still fugly, but it lets me test the @body hash at least. If you have a better way of doing this, or a way to make that look prettier, please let me know!