Rails - как вы протестируете ActionMailer, отправили конкретное письмо в тестах
В настоящее время в моих тестах я делаю что-то вроде этого, чтобы проверить, отправлено ли электронное письмо в очередь
assert_difference('ActionMailer::Base.deliveries.size', 1) do
get :create_from_spreedly, {:user_id => @logged_in_user.id}
end
но если я действие контроллера может отправлять два разных письма, то есть один для пользователя, если регистрация прекрасна или уведомление администратора, если что-то пошло не так - как я могу проверить, какой из них действительно отправлен. Приведенный выше код будет проходить независимо.
Ответы
Ответ 1
При использовании ActionMailer во время тестов все письма помещаются в большой массив с именем deliveries
. То, что вы в основном делаете (и в основном достаточное), проверяет наличие электронных писем в массиве.
Но если вы хотите специально проверить наличие определенного электронного письма, вы должны знать, что на самом деле хранится в массиве. К счастью, сами электронные письма хранятся, поэтому вы можете проходить через массив и проверять каждое электронное письмо.
См. ActionMailer:: Base, чтобы узнать, какие методы настройки доступны, которые вы можете использовать для определения того, какие электронные письма присутствуют в массиве. Некоторые из наиболее подходящих методов для вашего случая, вероятно, являются
-
recipients
: принимает один или несколько адресов электронной почты. Эти адреса будут отправлены по электронной почте. Устанавливает заголовок To:.
-
subject
: тема вашего письма. Устанавливает заголовок Subject:.
Ответ 2
Начиная с рельсов 3 ActionMailer :: Base.deliveries является массивом Mail :: Message. Из почтовой документации:
# mail['from'] = '[email protected]'
# mail[:to] = '[email protected]'
# mail.subject 'This is a test email'
# mail.body = 'This is a body'
#
# mail.to_s #=> "From: [email protected]\r\nTo: [email protected]
От этого должно быть легко проверить свою почту в интеграции
mail = ActionMailer::Base.deliveries.last
assert_equal '[email protected]', mail['from'].to_s
assert_equal '[email protected]', mail['to'].to_s
Ответ 3
Используя текущий синтаксис Rspec, я закончил использовать следующее:
last_email = ActionMailer::Base.deliveries.last
expect(last_email.to).to eq ['[email protected]']
expect(last_email.subject).to have_content 'Welcome'
Контекст моего теста был спецификацией функции, где я хотел убедиться, что после регистрации было отправлено приветственное письмо пользователю.
Ответ 4
База тестов shoulda имеет отличный помощник, который позволяет вам утверждать определенные условия для отправленного сообщения электронной почты. Да, вы можете сделать это самостоятельно с помощью ActionMailer.deliveries, но shoulda делает все это одним аккуратным небольшим блоком.
Ответ 5
Немного поздно, но это может помочь другим:
Вы можете использовать Email-spec, набор совпадений Rspec/Minitest и шаги Cucumber.
Ответ 6
Вот лучший способ, который я нашел для этого.
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)
и т.д. Что это!