ทดสอบการส่งอีเมลใน Django [ปิด]


92

ฉันต้องการทดสอบว่าแอปพลิเคชัน Django ของฉันส่งอีเมลพร้อมเนื้อหาที่ถูกต้องหรือไม่ ฉันไม่ต้องการพึ่งพาระบบภายนอก (เช่นบัญชีgmailเฉพาะกิจ) เนื่องจากฉันไม่ได้ทดสอบบริการอีเมลจริง ...

ฉันอาจต้องการเก็บอีเมลไว้ในเครื่องภายในโฟลเดอร์ที่ส่งไป มีเคล็ดลับอย่างไรในการบรรลุเป้าหมาย


ผู้ดูแล: โปรดล็อกคำถามนี้ มีการเพิ่มสแปมจำนวนมากในคำตอบโดยเสนอวิธีแก้ปัญหาที่ซับซ้อนอย่างน่าขันเพียงเพื่อส่งเสริมบริการภายนอก
nemesisdesign

คำตอบ:


42

คุณสามารถใช้แบ็กเอนด์ของไฟล์เพื่อส่งอีเมลซึ่งเป็นโซลูชันที่มีประโยชน์มากสำหรับการพัฒนาและทดสอบ อีเมลไม่ถูกส่ง แต่เก็บไว้ในโฟลเดอร์ที่คุณระบุได้!


1
ข้อมูลเพิ่มเติมเกี่ยวกับแบ็กเอนด์อีเมล: docs.djangoproject.com/en/dev/topics/email/#email-backends บางครั้งแม้แต่คอนโซลแบ็กเอนด์ธรรมดาก็เพียงพอแล้ว ..
Jeewes

1
แต่มีวิธีเข้าถึงอีเมลที่สร้างขึ้นระหว่างการทดสอบ (อัตโนมัติ) หรือไม่?
Overdrivr

184

กรอบทดสอบ Django มีบางส่วนที่สร้างขึ้นในผู้ช่วยเหลือที่จะช่วยให้คุณมีการทดสอบบริการ e-mail

ตัวอย่างจากเอกสาร (เวอร์ชันสั้น):

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.',
            'from@example.com', ['to@example.com'],
            fail_silently=False)
        self.assertEqual(len(mail.outbox), 1)
        self.assertEqual(mail.outbox[0].subject, 'Subject here')

3
+1 คำตอบที่ดี แต่ฉันไม่มีประโยชน์สำหรับกรณีที่ซับซ้อนเมื่อsend_mailไม่สามารถใช้งานได้
santiagobasulto

3
เอกสารที่แม่นยำยิ่งขึ้นอยู่ที่นี่: docs.djangoproject.com/en/1.8/topics/email/#in-memory-backend
nimiq

3
วิธีที่คุณจะทำเช่นนี้หากการทดสอบฟังก์ชั่นที่โทร send_mail ของคุณและคุณจึงไม่สามารถเข้าถึงmail?
Matt D

3
@MatthewDrill คุณยังสามารถเข้าถึงmail.outboxเมื่อsend_mailถูกเรียกใช้ในฟังก์ชันอื่น
pymarco

2
@pymarco หากคุณนำเข้าอีเมลจากคอร์mail.outbox[0].bodyจะแสดงอีเมลที่ส่งแม้ว่าsend_mailจะดำเนินการที่อื่นก็ตาม
Rob

17

หากคุณกำลังทดสอบหน่วยวิธีแก้ปัญหาที่ดีที่สุดคือใช้แบ็กเอนด์ในหน่วยความจำที่จัดเตรียมโดย django

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

ใช้ในกรณีที่ใช้เป็นอุปกรณ์py.test

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

ในการทดสอบแต่ละครั้งการทดสอบmail.outboxจะถูกรีเซ็ตด้วยเซิร์ฟเวอร์ดังนั้นจึงไม่มีผลข้างเคียงระหว่างการทดสอบ

from django.core import mail

def test_send(self):
    mail.send_mail('subject', 'body.', 'from@example.com', ['to@example.com'])
    assert len(mail.outbox) == 1

def test_send_again(self):
    mail.send_mail('subject', 'body.', 'from@example.com', ['to@example.com'])
    assert len(mail.outbox) == 1

8

ใช้MailHog

แรงบันดาลใจจาก MailCatcher ติดตั้งง่ายขึ้น

สร้างขึ้นด้วย Go - MailHog ทำงานโดยไม่ต้องติดตั้งบนหลายแพลตฟอร์ม


นอกจากนี้ยังมีส่วนประกอบที่เรียกว่าJim , MailHog Chaos Monkeyซึ่งช่วยให้คุณสามารถทดสอบการส่งอีเมลที่มีปัญหาต่างๆที่เกิดขึ้น:

จิมทำอะไรได้บ้าง?

  • ปฏิเสธการเชื่อมต่อ
  • จำกัด อัตราการเชื่อมต่อ
  • ปฏิเสธการรับรองความถูกต้อง
  • ปฏิเสธผู้ส่ง
  • ปฏิเสธผู้รับ

อ่านข้อมูลเพิ่มเติมเกี่ยวกับเรื่องนี้ที่นี่


(ซึ่งแตกต่างจาก mailcatcher ดั้งเดิมซึ่งล้มเหลวกับฉันเมื่อส่งอีเมลที่มีอีโมจิซึ่งเข้ารหัสเป็น UTF-8และไม่ได้รับการแก้ไขจริงๆในรุ่นปัจจุบัน MailHog ก็ใช้งานได้)


5

สำหรับโปรเจ็กต์ใด ๆ ที่ไม่ต้องส่งไฟล์แนบฉันใช้django-mailerซึ่งมีประโยชน์ของอีเมลขาออกทั้งหมดที่ลงท้ายด้วยคิวจนกว่าฉันจะเริ่มการส่งและแม้ว่าจะถูกส่งไปแล้วพวกเขาก็ถูกบันทึก - ซึ่งทั้งหมดนี้สามารถมองเห็นได้ในผู้ดูแลระบบทำให้ง่ายต่อการตรวจสอบอย่างรวดเร็วว่ารหัสอีเมลที่คุณพยายามจะปิดลงใน intertubes คืออะไร


นอกจากนั้นวัตถุข้อความที่สร้างโดย django-mailer หมายความว่าคุณสามารถ prod (และตรวจสอบเนื้อหา) ในการทดสอบหน่วยได้เช่นกัน (ฉันรู้ว่ามีการรองรับกล่องจดหมายขาออกในชุดทดสอบสำหรับกล่องจดหมายจำลอง แต่การใช้ django-mailer ไม่ได้ อย่าส่งเมลเว้นแต่คำสั่งการจัดการจะส่งซึ่งหมายความว่าคุณไม่สามารถใช้วัตถุกล่องจดหมายนั้นได้)
Steve Jalim

อัปเดตอายุต่อจากคำตอบเดิมของฉัน: github.com/SmileyChris/django-mailer-2รองรับไฟล์แนบด้วย
Steve Jalim

4

Django ยังมีแบ็กเอนด์อีเมลในหน่วยความจำ รายละเอียดเพิ่มเติมในเอกสารภายใต้แบ็กเอนด์ในหน่วยความจำ สิ่งนี้มีอยู่ใน Django 1.6 ไม่แน่ใจว่ามีอยู่ในสิ่งใดก่อนหน้านี้หรือไม่



1

filebased.EmailBackendคาดไม่กี่ชิ้นที่นี่ด้วยกันนี่คือการติดตั้งตรงไปตรงมาบนพื้นฐานของ สิ่งนี้จะแสดงมุมมองรายการที่เชื่อมโยงไปยังไฟล์บันทึกแต่ละไฟล์ซึ่งมีชื่อไฟล์ที่ประทับเวลาได้อย่างสะดวก การคลิกลิงก์ในรายการจะแสดงข้อความนั้นในเบราว์เซอร์ (ดิบ):

การตั้งค่า

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

ดู

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})

เทมเพลต

{% 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"),

0

ทำไมไม่เริ่มเซิร์ฟเวอร์ SMTP ที่เรียบง่ายของคุณเองโดยรับช่วงจากsmtpd.SMTPServerและ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 ถูกเรียกเมื่อใดก็ตามที่เซิร์ฟเวอร์ SMTP ของคุณได้รับคำร้องขอเมลคุณสามารถทำอะไรก็ได้ที่คุณต้องการ

ในโค้ดทดสอบให้ทำดังนี้:

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

ก็อย่าลืมโดยโทรไปสิ้นสุดการวนรอบ asyncore (การหยุดเซิร์ฟเวอร์จากการฟัง)close()asyncore.dispatchersmtp_server.close()


0

หากคุณมีเซิร์ฟเวอร์ TomCat หรือเครื่องมือ servlet อื่น ๆ แนวทางที่ดีคือ "Post Hoc" ซึ่งเป็นเซิร์ฟเวอร์ขนาดเล็กที่มีลักษณะคล้ายกับแอปพลิเคชันเหมือนกับเซิร์ฟเวอร์ SMTP แต่มีอินเทอร์เฟซผู้ใช้ที่ช่วยให้คุณสามารถดูและ ตรวจสอบข้อความอีเมลที่ส่ง เป็นโอเพ่นซอร์สและใช้ได้อย่างอิสระ

ค้นหาได้ที่: Post Hoc GitHub Site

ดูบล็อกโพสต์: PostHoc: การทดสอบแอปที่ส่งอีเมล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.