Rails - Как вы тестируете ActionMailer отправил конкретное письмо в тестах - PullRequest
45 голосов
/ 14 января 2010

В настоящее время в моих тестах я делаю что-то подобное, чтобы проверить, стоит ли в очереди электронная почта для отправки

assert_difference('ActionMailer::Base.deliveries.size', 1) do       
  get :create_from_spreedly, {:user_id => @logged_in_user.id}
end

но если действие контроллера может отправить два разных электронных письма, то есть одно пользователю, если регистрация прошла нормально, или уведомление администратору, если что-то пошло не так, - как я могу проверить, какое из них действительно было отправлено. Код выше пройдет независимо.

Ответы [ 6 ]

73 голосов
/ 19 августа 2010

По состоянию на рельсы 3 ActionMailer :: Base.deliveries является массивом Mail :: Message. Из почтовой документации :

#  mail['from'] = 'mikel@test.lindsaar.net'
#  mail[:to]    = 'you@test.lindsaar.net'
#  mail.subject 'This is a test email'
#  mail.body    = 'This is a body'
# 
#  mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...

Из этого должно быть легко проверить почту в интеграции

mail = ActionMailer::Base.deliveries.last

assert_equal 'mikel@test.lindsaar.net', mail['from'].to_s

assert_equal 'you@test.lindsaar.net', mail['to'].to_s
27 голосов
/ 14 января 2010

При использовании ActionMailer во время тестов все письма помещаются в большой массив с именем deliveries.То, что вы в основном делаете (и в основном достаточно), это проверка наличия в массиве писем.Но если вы хотите специально проверить определенную электронную почту, вы должны знать, что на самом деле хранится в массиве.К счастью, сами электронные письма хранятся, поэтому вы можете перебирать массив и проверять каждое электронное письмо.

См. ActionMailer :: Base , чтобы увидеть, какие методы конфигурации доступны, которые вы можете использоватьопределить, какие электронные письма присутствуют в массиве.Некоторые из наиболее подходящих методов для вашего случая, вероятно, являются

  • recipients: занимает один или несколько адресов электронной почты.По этим адресам будет доставлено ваше письмо.Устанавливает заголовок To:
  • subject: тема вашего электронного письма.Устанавливает заголовок Subject:
18 голосов
/ 21 июня 2013

Используя текущий синтаксис Rspec, я использовал следующее:

last_email = ActionMailer::Base.deliveries.last
expect(last_email.to).to eq ['test@example.com']
expect(last_email.subject).to have_content 'Welcome'

Контекст моего теста представлял собой спецификацию, в которой я хотел убедиться, что приветственное письмо было отправлено пользователю после регистрации.

3 голосов
/ 14 января 2010

Тестовый фреймворк shoulda имеет отличный помощник, который позволяет вам утверждать определенные условия в отношении отправленного электронного письма. Да, вы можете сделать это самостоятельно с помощью ActionMailer.deliveries, но следует сделать все это одним аккуратным небольшим блоком

2 голосов
/ 16 августа 2013

Немного поздно, но это может помочь другим:

Вы можете использовать Email-spec , набор Rspec / Minitest matchers и огуречных шагов.

1 голос
/ 12 мая 2010

Вот лучший способ, который я нашел для этого.

1) Включите плагин action mailer следующим образом:

script/plugin install git://github.com/AnthonyCaliendo/action_mailer_callbacks.git

Я на самом деле не использую основные функции плагина, но он обеспечивает хорошую функциональность, позволяя выяснить, какой метод использовался для отправки электронного письма.

2) Теперь вы можете поместить несколько методов в свой test_helper.rb, например:

  def assert_sent(method_name)
    assert sent_num_times(method_name) > 0
  end

  def assert_not_sent(method_name)
    assert sent_num_times(method_name) == 0
  end

  def assert_sent_once(method_name)
    assert sent_num_times(method_name) == 1
  end

  def sent_num_times(method_name)
    count = 0
    @emails.each do |email|
      count += 1 if method_name == email.instance_variable_get("@method_name")
    end
    count
  end

3) Теперь вы можете написать сладкие тесты, подобные этому:

require 'test_helper'
class MailingTest < ActionController::IntegrationTest

  def setup
    @emails = ActionMailer::Base.deliveries
    @emails.clear
  end

  test "should send a mailing" do
    assert_difference "Mailing.count", 1 do
      feeds(:feed1).generate_mailing
    end

    assert_sent_once "broadcast"
    assert_not_sent "failed_mailing"
  end
end

Здесь «broadcast» и «mailing_failed» - это имена методов в моем классе ActionMailer :: Base. Это те, которые вы обычно используете, звоня по номеру Mailer.deliver_broadcast(some_data) или Mailer.deliver_failed_mailing(some_data) и т. Д. Вот и все!

...