Skip to content
Browse files

Restore test deliveries properly in ActionMailer.

`ActionMailer::Base.delivery_method` and
`ActionMailer::Base.perform_deliveries` have leaked states.

"delivery method can be customized per instance" and "delivery method
can be customized in subclasses not changing the parent" in
delivery_methods_test.rb will fail if test_helper_test.rb (in which
TestHelperMailerTest is inherited from ActionMailer::TestCase) runs
before it.
  • Loading branch information...
1 parent ecd4151 commit c4f4123ef45463a09b36186047dbdc82f933fe46 @zuhao zuhao committed Jun 7, 2014
Showing with 8 additions and 0 deletions.
  1. +8 −0 actionmailer/lib/action_mailer/test_case.rb
View
8 actionmailer/lib/action_mailer/test_case.rb
@@ -20,6 +20,7 @@ module Behavior
class_attribute :_mailer_class
setup :initialize_test_deliveries
setup :set_expected_mail
+ teardown :restore_test_deliveries
end
module ClassMethods
@@ -54,8 +55,15 @@ def determine_default_mailer(name)
protected
def initialize_test_deliveries
+ @old_delivery_method = ActionMailer::Base.delivery_method
+ @old_perform_deliveries = ActionMailer::Base.perform_deliveries
ActionMailer::Base.delivery_method = :test
ActionMailer::Base.perform_deliveries = true
+ end
+
+ def restore_test_deliveries
+ ActionMailer::Base.delivery_method = @old_delivery_method
+ ActionMailer::Base.perform_deliveries = @old_perform_deliveries
ActionMailer::Base.deliveries.clear
end

1 comment on commit c4f4123

@mgodwin

Hi - could more context be provided on this changeset?

I'm noticing that I'm getting intermittent test failures with this change after upgrading from rails 4.1 b/c the deliveries array isn't cleared out prior to tests running. I had written quite a few tests that asserted that the deliveries array is empty? since the guides and other docs say that the actionmailer tests are reset automatically. (Although, combing through the docs now, it doesn't seem extremely clear that it states when they're reset...)

It seems surprising to me that more people haven't run into test failures here, since if you turn on randomized test ordering the following sequence is a definite possibility:

  1. A controller test adds mail to the deliveries array
  2. The next test that runs is in a mailer test, asserts ActionMailer::Base.deliveries.empty?
  3. Failure because deliveries is not cleared in initialization anymore

I'm willing to concede that maybe I'm doing something wrong, so - should I not be using assert ActionMailer::Base.deliveries.empty? anymore?

The thought does occur to me though - it seems more problematic that the example provided in the rails guides could now result in a false positive (test passing when it should have failed), since the deliveries array may not actually be empty.

example from rails guides:

require 'test_helper'

class UserMailerTest < ActionMailer::TestCase
  test "invite" do
    # Send the email, then test that it got queued
    email = UserMailer.create_invite('me@example.com',
                                     'friend@example.com', Time.now).deliver_now
    assert_not ActionMailer::Base.deliveries.empty?

    # Test the body of the sent email contains what we expect it to
    assert_equal ['me@example.com'], email.from
    assert_equal ['friend@example.com'], email.to
    assert_equal 'You have been invited by me@example.com', email.subject
    assert_equal read_fixture('invite').join, email.body.to_s
  end
end
Please sign in to comment.
Something went wrong with that request. Please try again.