Menguji pengiriman email di Django [ditutup]

90

Saya perlu menguji bahwa aplikasi Django saya mengirimkan email dengan isi yang benar. Saya tidak ingin bergantung pada sistem eksternal (seperti akun gmail ad-hoc ), karena saya tidak menguji layanan email yang sebenarnya ...

Saya ingin, mungkin, menyimpan email secara lokal, di dalam folder saat dikirim. Ada tip tentang bagaimana mencapainya?

RadiantHex
sumber
Moderator: tolong kunci pertanyaan ini. Banyak spam ditambahkan dalam jawaban, mengusulkan solusi yang sangat rumit hanya untuk mempromosikan layanan eksternal.
nemesisdesign

Jawaban:

43

Anda dapat menggunakan file backend untuk mengirim email yang merupakan solusi yang sangat berguna untuk pengembangan dan pengujian; email tidak dikirim tetapi disimpan dalam folder yang dapat Anda tentukan!

Bernhard Vallant
sumber
1
Info selengkapnya tentang backend email: docs.djangoproject.com/en/dev/topics/email/#email-backends . Kadang-kadang bahkan backend konsol sederhana sudah cukup ..
Jeewes
1
Tetapi apakah ada cara untuk mengakses email yang dihasilkan selama pengujian (otomatis)?
Overdrivr
182

Kerangka uji Django memiliki beberapa pembantu bawaan untuk membantu Anda menguji layanan email .

Contoh dari dokumen (versi singkat):

from django.core import mail
from django.test import TestCase

class EmailTest(TestCase):
    def test_send_email(self):
        mail.send_mail('Subject here', 'Here is the message.',
            '[email protected]', ['[email protected]'],
            fail_silently=False)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Subject here')
Davor Lucic
sumber
3
+1 Jawaban yang bagus. Tapi saya tidak berguna untuk kasus yang rumit, ketika send_mailtidak bisa digunakan.
santiagobasulto
3
Lebih tepatnya, dokumennya
nimiq
2
Bagaimana Anda melakukan ini jika Anda menguji fungsi yang memanggil send_mail dan oleh karena itu Anda tidak dapat mengakses mail?
Matt D
3
@MatthewDrill Anda masih dapat mengakses mail.outboxsaat send_maildipanggil di fungsi lain.
pymarco
2
@pymarco Jika Anda mengimpor email dari inti, mail.outbox[0].bodyakan menampilkan email yang dikirim meskipun send_maildilakukan di tempat lain.
Rob
17

Jika Anda ingin menguji unit, solusi terbaik adalah menggunakan backend dalam memori yang disediakan oleh django.

EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'

Ambil kasus menggunakannya sebagai perlengkapan py.test

@pytest.fixture(autouse=True)
def email_backend_setup(self, settings):
    settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'  

Di setiap pengujian, di mail.outbox-reset dengan server, sehingga tidak ada efek samping antar pengujian.

from django.core import mail

def test_send(self):
    mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
    assert len(mail.outbox) == 1

def test_send_again(self):
    mail.send_mail('subject', 'body.', '[email protected]', ['[email protected]'])
    assert len(mail.outbox) == 1
Kiril
sumber
8

Gunakan MailHog

Terinspirasi oleh MailCatcher, lebih mudah dipasang.

Dibangun dengan Go - MailHog berjalan tanpa instalasi pada banyak platform.


Selain itu, ia memiliki komponen yang disebut Jim , MailHog Chaos Monkey , yang memungkinkan Anda menguji pengiriman email dengan berbagai masalah yang terjadi:

Apa yang bisa dilakukan Jim?

  • Tolak koneksi
  • Tingkat koneksi batas
  • Tolak otentikasi
  • Tolak pengirim
  • Tolak penerima

Baca lebih lanjut di sini .


(Tidak seperti mailcatcher asli, yang gagal pada saya saat mengirim email dengan emoji, dikodekan dalam UTF-8 dan TIDAK benar-benar diperbaiki dalam rilis saat ini, MailHog hanya berfungsi.)

Greg Dubicki
sumber
5

Untuk proyek apa pun yang tidak memerlukan pengiriman lampiran, saya menggunakan django-mailer , yang memiliki keuntungan dari semua email keluar yang berakhir dalam antrian sampai saya memicu pengirimannya, dan bahkan setelah dikirim, mereka kemudian masuk - semuanya dapat dilihat di Admin, memudahkan untuk memeriksa dengan cepat kode email apa yang Anda coba aktifkan ke dalam intertubes.

Steve Jalim
sumber
Lebih jauh dari itu, objek Pesan yang dibuat oleh django-mailer berarti Anda dapat memproduksinya (dan memeriksa isinya) dalam pengujian unit juga (saya tahu bahwa ada dukungan kotak surat keluar dalam rangkaian percobaan untuk kotak surat tiruan, tetapi menggunakan django-mailer tidak mengirim email kecuali jika perintah manajemen mengirimkannya, yang berarti Anda tidak dapat menggunakan objek kotak surat itu)
Steve Jalim
Pembaruan, usia sejak jawaban asli saya: github.com/SmileyChris/django-mailer-2 juga mendukung lampiran
Steve Jalim
4

Django juga memiliki backend email dalam memori. Detail selengkapnya ada di dokumen di bawah Backend dalam memori . Ini ada di Django 1.6 tidak yakin apakah itu ada sebelumnya.

Josh K
sumber
1

Mengikat beberapa bagian di sini bersama-sama, berikut adalah penyiapan langsungnya filebased.EmailBackend . Ini membuat tampilan daftar yang tertaut ke file log individual, yang memiliki nama file yang diberi stempel waktu dengan mudah. Mengklik tautan dalam daftar menampilkan pesan itu di browser (mentah):

Pengaturan

EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend"
EMAIL_FILE_PATH = f"{MEDIA_ROOT}/email_out"

Melihat

import os

from django.conf import settings
from django.shortcuts import render

def mailcheck(request):

    path = f"{settings.MEDIA_ROOT}/email_out"
    mail_list = os.listdir(path)

    return render(request, "mailcheck.html", context={"mail_list": mail_list})

Template

{% if mail_list %}
  <ul>
  {% for msg in mail_list %}
    <li>
      <a href="{{ MEDIA_URL }}email_out/{{msg}}">{{ msg }}</a>
    </li>
  {% endfor %}
  </ul>
{% else %}
  No messages found.
{% endif %}

url

path("mailcheck/", view=mailcheck, name="mailcheck"),
shacker
sumber
0

Mengapa tidak memulai Server SMTP Anda sendiri yang sangat sederhana dengan mewarisi dari smtpd.SMTPServerdan threading.Thread:

class TestingSMTPServer(smtpd.SMTPServer, threading.Thread):
    def __init__(self, port=25):
        smtpd.SMTPServer.__init__(
            self,
            ('localhost', port),
            ('localhost', port),
            decode_data=False
        )
        threading.Thread.__init__(self)

    def process_message(self, peer, mailfrom, rcpttos, data, **kwargs):
        self.received_peer = peer
        self.received_mailfrom = mailfrom
        self.received_rcpttos = rcpttos
        self.received_data = data

    def run(self):
        asyncore.loop()

process_message dipanggil setiap kali Server SMTP Anda menerima permintaan email, Anda dapat melakukan apa pun yang Anda inginkan di sana.

Dalam kode pengujian, lakukan sesuatu seperti ini:

smtp_server = TestingSMTPServer()
smtp_server.start()
do_thing_that_would_send_a_mail()
smtp_server.close()
self.assertIn(b'hello', smtp_server.received_data)

Hanya ingat untuk close()yang asyncore.dispatcherdengan memanggil smtp_server.close()untuk mengakhiri loop asyncore (menghentikan server dari mendengarkan).

frogcoder.dll
sumber
0

Jika Anda memiliki server TomCat yang tersedia, atau mesin servlet lainnya, maka pendekatan yang bagus adalah "Post Hoc" yang merupakan server kecil yang terlihat ke aplikasi persis seperti server SMTP, tetapi ini menyertakan antarmuka pengguna yang memungkinkan Anda untuk melihat dan periksa pesan email yang dikirim. Ini open source dan tersedia secara gratis.

Temukan di: Post Hoc GitHub Site

Lihat entri blog: PostHoc: Menguji Aplikasi yang Mengirim Email

AgilePro
sumber