web-dev-qa-db-fra.com

Rails - Comment testez-vous ActionMailer a envoyé un e-mail spécifique lors des tests

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.

46
robodisco

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 :.
27
Veger

À 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
76
todd

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.

18
Neal

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é

3
RyanWilcox

Un peu tard, mais cela peut aider les autres:

Vous pouvez utiliser Email-spec , une collection d'apparieurs Rspec/Minitest et d'étapes Cucumber.

2
guapolo

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!

1
Brian Armstrong