Тестування надсилання електронної пошти в Django [закрито]


90

Мені потрібно перевірити, що моя програма Django надсилає електронні листи з правильним вмістом. Я не хочу покладатися на зовнішні системи (наприклад, на спеціальний обліковий запис Gmail ), оскільки я не тестую фактичну службу електронної пошти ...

Можливо, я хотів би зберігати електронні листи локально, у папці, коли вони надсилаються. Будь-яка порада, як цього досягти?


Модератори: заблокуйте це питання. У відповіді додається багато спаму, пропонуючи смішно складні рішення лише для просування зовнішніх послуг.
nemesisdesign

Відповіді:


43

Ви можете використовувати сервер файлу для надсилання електронних листів, що є дуже зручним рішенням для розробки та тестування; електронні листи не надсилаються, а зберігаються в папці, яку ви можете вказати!


1
Більше інформації про електронну пошту: docs.djangoproject.com/en/dev/topics/email/#email-backends . Іноді достатньо навіть простої консольної консолі ..
Jeewes

1
Але чи є спосіб отримати доступ до сформованого повідомлення електронної пошти під час (автоматизованого) тестування?
Overdrivr

183

Тестова система Django має вбудовані помічники, які допоможуть вам у тестуванні служби електронної пошти .

Приклад із документів (коротка версія):

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

2
Як ви можете це зробити, якщо ви тестуєте функцію, яка викликає send_mail, і ви не можете отримати доступ mail?
Matt D

3
@MatthewDrill ви все ще можете отримати доступ, mail.outboxколи send_mailвикликається інша функція.
pymarco

2
@pymarco Якщо ви імпортуєте пошту з ядра, mail.outbox[0].bodyпокаже вам надісланий електронний лист, навіть якщо send_mailце зроблено в іншому місці.
Роб

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 працює без установки на декількох платформах.


Крім того, у ньому є компонент під назвою Джим , мавпа MailHog Chaos Monkey , який дозволяє перевірити надсилання електронних листів із різними проблемами:

Що може зробити Джим?

  • Відхилити з'єднання
  • Зв'язок з обмеженою швидкістю
  • Відхилити автентифікацію
  • Відхилити відправників
  • Відхилити одержувачів

Детальніше про це читайте тут .


(На відміну від оригінального поштового лову, який мені не вдався під час надсилання електронних листів із смайликами, закодованими в UTF-8, і це НЕ БУЛО виправлено в поточному випуску, MailHog просто працює.)


5

Для будь-якого проекту, який не вимагає надсилання вкладень, я використовую django-mailer , який має перевагу, що всі вихідні електронні листи потрапляють у чергу, поки я не ініціюю їх відправлення, і навіть після того, як вони будуть відправлені, вони потім реєструються - все це видно в адміністраторі, що дозволяє легко швидко перевірити, який код електронної пошти намагається запустити в міжтрубках.


Окрім цього, об’єкти Message, створені django-mailer, означають, що ви можете їх продукувати (і перевіряти їх вміст) і в модульних тестах (я знаю, що в наборі тестів для фіктивної поштової скриньки є підтримка вихідних поштових скриньок, але використання django-mailer не не надсилає пошту, якщо команда управління не надсилає її, а це означає, що ви не можете використовувати цей об'єкт поштової скриньки)
Стів Джалім,

Оновлення, вік від моєї оригінальної відповіді: github.com/SmileyChris/django-mailer-2 теж підтримує вкладення
Стів Джалім,

4

Django також має внутрішній сервер електронної пошти в пам'яті. Детальніше в документах у розділі In-memory backend . Це присутнє в 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 або інший движок сервлетів, то хорошим підходом є "Post Hoc", який є невеликим сервером, який виглядає в додатку точно так само, як SMTP-сервер, але він включає користувальницький інтерфейс, який дозволяє переглядати та перевірити надіслані повідомлення електронної пошти. Він є відкритим і вільно доступний.

Знайдіть його на: Post Hoc GitHub Site

Дивіться допис у блозі: PostHoc: Тестування програм, що надсилають електронну пошту

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.