2010-01-14 4 views
37

Attualmente nel mio test che faccio qualcosa di simile per verificare se un messaggio di posta è in coda per essere inviatoRails - Come si fa a testare ActionMailer inviato una e-mail specifico nei test

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

ma se ia azione di controllo può inviare due e-mail diverse, cioè una per l'utente se la registrazione va bene o una notifica da admin se qualcosa è andato storto - come posso testare quale effettivamente è stato inviato. Il codice sopra sarebbe passato a prescindere.

risposta

22

Quando si utilizza ActionMailer durante i test, tutte le mail vengono inserite in un grande array denominato deliveries. Quello che stai facendo fondamentalmente (ed è sufficiente per lo più) è il controllo della presenza di e-mail nell'array. Ma se si desidera verificare specificamente una determinata e-mail, è necessario sapere cosa è effettivamente memorizzato nell'array. Fortunatamente le e-mail stesse sono archiviate, quindi puoi scorrere l'array e controllare ogni e-mail.

Vedere ActionMailer::Base per vedere quali metodi di configurazione sono disponibili, che è possibile utilizzare per determinare quali messaggi di posta elettronica sono presenti nell'array. Alcuni dei metodi più adatti per il tuo caso probabilmente sono

  • recipients: accetta uno o più indirizzi di posta elettronica. Questi indirizzi sono dove verrà recapitata la tua email. Imposta l'intestazione To :.
  • subject: oggetto della tua email. Imposta l'oggetto: intestazione.
3

Il framework di test shoulda ha un eccellente supporto che consente di definire alcune condizioni relative a un'e-mail inviata. Sì, puoi farlo tu stesso con ActionMailer.deliveries, ma shoulda rende tutto un piccolo blocco pulito

+1

questo è il matcher 'have_sent_email' http://www.rubydoc.info/gems/shoulda/2.11.3/Shoulda/ActionMailer/Matchers (ad esempio' it {dovrebbe avere_sent_email.with_subject (/ spam /). From (' [email protected] '). with_body (/ spam /). a ([email protected]')} ' –

1

Ecco il modo migliore che ho trovato per farlo.

1) Inserisci il plugin action mailer callbacks in questo modo:

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

Io in realtà non usare le caratteristiche principali del plugin, ma fornisce la bella funzionalità di essere in grado di capire quale metodo è stato utilizzato per inviare un'email.

2) Ora potete mettere alcuni metodi in test_helper.rb come questo:

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) Ora è possibile scrivere i test dolci come questo:

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 

Qui "broadcast" e "mailing_failed" sono i nomi dei metodi nella mia classe ActionMailer :: Base. Questi sono quelli che normalmente usi chiamando Mailer.deliver_broadcast(some_data) o Mailer.deliver_failed_mailing(some_data) ecc. Questo è tutto!

60

As of rails 3 ActionMailer :: Base.deliveries è una matrice di Mail :: Message's.Dalla documentazione 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: [email protected] 

Da che dovrebbe essere facile per testare la posta di in un'integrazione

mail = ActionMailer::Base.deliveries.last 

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

assert_equal '[email protected]', mail['to'].to_s 
+1

Puoi anche usare:" asserire ActionMailer :: Base.deliveries.size> = 1 (o == 2) "per controllare più mail vengono inviati. e per verificare più soggetti, e le e-mail utilizzano" ActionMailer :: Base.deliveries.last (2) " –

15

Utilizzando la sintassi Rspec corrente, ho finito per usare il seguente:

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

Il contesto del mio test era una funzione specifica in cui volevo assicurarmi che una mail di benvenuto fosse inviata a un utente dopo esserti registrato.

1

Un po 'in ritardo, ma può aiutare gli altri:

Si potrebbe usare Email-spec, una raccolta di matchers Rspec/MINITEST e passi cetriolo.

Problemi correlati