Actuellement, dans mes tests, je fais quelque chose comme ça pour tester si un e-mail est mis en file d'attente pour être envoyé
assert_difference('ActionMailer::Base.deliveries.size', 1) do
get :create_from_spreedly, {:user_id => @logged_in_user.id}
end
mais si une action du contrôleur peut envoyer deux e-mails différents, c'est-à-dire un à l'utilisateur si l'inscription se passe bien ou une notification à l'administrateur en cas de problème - comment puis-je tester lequel a effectivement été envoyé. Le code ci-dessus passerait malgré tout.
Lorsque vous utilisez ActionMailer pendant les tests, tous les e-mails sont placés dans un grand tableau appelé deliveries
. Ce que vous faites (et cela suffit principalement), c'est de vérifier si des e-mails sont présents dans le tableau. Mais si vous souhaitez vérifier spécifiquement un certain e-mail, vous devez savoir ce qui est réellement stocké dans le tableau. Heureusement, les e-mails eux-mêmes sont stockés, vous pouvez donc parcourir le tableau et vérifier chaque e-mail.
Voir ActionMailer :: Base pour voir quelles méthodes de configuration sont disponibles, que vous pouvez utiliser pour déterminer quels e-mails sont présents dans le tableau. Certaines des méthodes les plus adaptées à votre cas sont probablement
recipients
: prend une ou plusieurs adresses e-mail. Ces adresses sont le lieu de livraison de votre e-mail. Définit l'en-tête To :.subject
: l'objet de votre e-mail. Définit l'en-tête Subject :.À partir de Rails 3 ActionMailer :: Base.deliveries est un tableau de Mail :: Message. À partir de la documentation de messagerie :
# 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: you@...
De là, il devrait être facile de tester vos e-mails dans une intégration
mail = ActionMailer::Base.deliveries.last
assert_equal '[email protected]', mail['from'].to_s
assert_equal '[email protected]', mail['to'].to_s
En utilisant la syntaxe Rspec actuelle, j'ai fini par utiliser ce qui suit:
last_email = ActionMailer::Base.deliveries.last
expect(last_email.to).to eq ['[email protected]']
expect(last_email.subject).to have_content 'Welcome'
Le contexte de mon test était une spécification de fonctionnalité où je voulais m'assurer qu'un e-mail de bienvenue était envoyé à un utilisateur après son inscription.
Le framework de test shoulda a un excellent assistant qui vous permet d'affirmer certaines conditions concernant un e-mail envoyé. Oui, vous pouvez le faire vous-même avec ActionMailer.deliveries, mais devrait tout faire en un petit bloc soigné
Un peu tard, mais cela peut aider les autres:
Vous pouvez utiliser Email-spec , une collection d'apparieurs Rspec/Minitest et d'étapes Cucumber.
Voici le meilleur moyen que j'ai trouvé pour le faire.
1) Incluez le plugin action mailer callbacks comme ceci:
script/plugin install git://github.com/AnthonyCaliendo/action_mailer_callbacks.git
Je n'utilise pas vraiment les principales fonctionnalités du plugin, mais il offre la fonctionnalité Nice de pouvoir déterminer quelle méthode a été utilisée pour envoyer un e-mail.
2) Vous pouvez maintenant mettre des méthodes dans votre test_helper.rb comme ceci:
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) Maintenant, vous pouvez écrire de doux tests comme celui-ci:
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
Ici "broadcast" et "mailing_failed" sont les noms des méthodes dans ma classe ActionMailer :: Base. Ce sont ceux que vous utilisez normalement en appelant Mailer.deliver_broadcast(some_data)
ou Mailer.deliver_failed_mailing(some_data)
etc. C'est tout!