Rails - Cómo probar ActionMailer envió un correo electrónico específico en tests


Actualmente en mis pruebas hago algo como esto para probar si un correo electrónico está en cola para ser enviado

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

Pero si una acción del controlador puede enviar dos correos electrónicos diferentes, es decir, uno al usuario si el registro va bien o una notificación al administrador si algo salió mal, ¿cómo puedo probar cuál realmente se envió? El código anterior pasaría de todos modos.

Author: John Bachir, 2010-01-14

6 answers

Cuando se usa el ActionMailer durante las pruebas, todos los correos se colocan en una gran matriz llamada deliveries. Lo que básicamente está haciendo (y es suficiente en su mayoría) es comprobar si los correos electrónicos están presentes en la matriz. Pero si desea comprobar específicamente para un cierto correo electrónico, usted tiene que saber lo que realmente se almacena en la matriz. Afortunadamente, los correos electrónicos se almacenan, por lo que puede iterar a través de la matriz y verificar cada correo electrónico.

Vea ActionMailer:: Base para ver qué configuración hay métodos disponibles, que puede usar para determinar qué correos electrónicos están presentes en la matriz. Algunos de los métodos más adecuados para su caso probablemente son

  • recipients: Toma una o más direcciones de correo electrónico. Estas direcciones son donde su correo electrónico será entregado a. Establece el encabezado A:.
  • subject: El asunto de tu correo electrónico. Establece el encabezado Subject:.
 24
Author: Veger,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 16:09:00

A partir de rails 3 ActionMailer:: Base.deliveries es una matriz de Mail:: Message. De la documentación de mail:

#  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@...

A partir de eso, debería ser fácil probar sus correos en una integración

mail = ActionMailer::Base.deliveries.last

assert_equal '[email protected]', mail['from'].to_s

assert_equal '[email protected]', mail['to'].to_s
 66
Author: todd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-18 19:11:13

Usando la sintaxis actual de Rspec, terminé usando lo siguiente:

last_email = ActionMailer::Base.deliveries.last
expect(last_email.to).to eq ['[email protected]']
expect(last_email.subject).to have_content 'Welcome'

El contexto de mi prueba fue una especificación de características en la que quería asegurarme de que se enviara un correo electrónico de bienvenida a un usuario después de registrarse.

 16
Author: Neal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-20 20:54:09

El marco de prueba shoulda tiene un excelente ayudante que le permite afirmar ciertas condiciones sobre un correo electrónico que se envió. Sí, podrías hacerlo tú mismo con ActionMailer.entregas, pero shoulda lo hace todo un pequeño bloque ordenado

 3
Author: RyanWilcox,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-14 16:30:40

Un poco tarde, pero puede ayudar a otros:

Puedes usar Email-spec, una colección de emparejadores Rspec/Minitest y pasos de pepino.

 2
Author: guapolo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-16 06:41:24

Aquí está la mejor manera que he encontrado para hacerlo.

1) Incluye el complemento callbacks de action mailer como este:

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

Realmente no uso las características principales del plugin, pero proporciona la buena funcionalidad de ser capaz de averiguar qué método se utilizó para enviar un correo electrónico.

2) Ahora puede poner algunos métodos en su test_helper.rb como este:

  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) Ahora puedes escribir pruebas dulces como esta:

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

Aquí "broadcast" y " mailing_failed" son los nombres de los métodos en mi clase ActionMailer::Base. Estos son los que normalmente usas llamando a Mailer.deliver_broadcast(some_data) o Mailer.deliver_failed_mailing(some_data) etc. ¡Eso es!

 1
Author: Brian Armstrong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-12 03:23:27