Muszę sprawdzić, czy moja aplikacja Django wysyła e-maile z poprawną zawartością. Nie chcę polegać na systemach zewnętrznych (takich jak ad-hoc konto Gmail ), ponieważ nie testuję samej usługi e-mail ...
Być może chciałbym przechowywać e-maile lokalnie, w folderze, gdy są wysyłane. Masz jakąś wskazówkę, jak to osiągnąć?
Odpowiedzi:
Możesz użyć zaplecza plików do wysyłania wiadomości e-mail, co jest bardzo wygodnym rozwiązaniem do programowania i testowania; wiadomości e-mail nie są wysyłane, ale przechowywane w folderze, który możesz określić!
źródło
Framework testowy Django ma wbudowanych pomocników, które pomogą Ci w testowaniu usługi e-mail .
Przykład z dokumentów (wersja skrócona):
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')
źródło
send_mail
nie można go użyć.mail
?mail.outbox
gdysend_mail
zostanie wywołana w innej funkcji.mail.outbox[0].body
wyświetli wysłaną wiadomość e-mail, nawet jeślisend_mail
jest to wykonywane gdzie indziej.Jeśli interesujesz się testowaniem jednostkowym, najlepszym rozwiązaniem jest użycie zaplecza In-memory dostarczanego przez django.
EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
Weź przypadek użycia go jako urządzenia py.test
@pytest.fixture(autouse=True) def email_backend_setup(self, settings): settings.EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
W każdym teście
mail.outbox
jest resetowany z serwerem, więc między testami nie ma żadnych skutków ubocznych.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
źródło
Użyj MailHog
Zawiera również komponent o nazwie Jim , MailHog Chaos Monkey , który umożliwia testowanie wysyłania wiadomości e-mail z różnymi problemami:
Przeczytaj więcej na ten temat tutaj .
(W przeciwieństwie do oryginalnego Mailcatchera, który zawiódł mnie podczas wysyłania e-maili z emoji, zakodowany w UTF-8 i NIE został naprawiony w bieżącej wersji, MailHog po prostu działa.)
źródło
W przypadku każdego projektu, który nie wymaga wysyłania załączników, używam django-mailer , który ma tę zaletę, że wszystkie wychodzące wiadomości e-mail trafiają do kolejki, dopóki nie wyzwolę ich wysłania, a nawet po ich wysłaniu są następnie rejestrowane - wszystko to jest widoczne w panelu administracyjnym, co ułatwia szybkie sprawdzenie, jaki kod e-mailowy próbuje odpalić w intertubach.
źródło
Django ma również zaplecze e-mail w pamięci. Więcej szczegółów w dokumentach w sekcji Backend w pamięci . Jest to obecne w Django 1.6, nie jestem pewien, czy jest obecne w czymkolwiek wcześniej.
źródło
Poprawianie SMTPLib do celów testowych może pomóc w testowaniu wysyłania wiadomości bez ich wysyłania.
źródło
Łącząc kilka elementów razem, oto prosta konfiguracja oparta na
filebased.EmailBackend
. Powoduje to wyświetlenie listy zawierającej łącza do poszczególnych plików dziennika, które mają wygodne nazwy plików ze znacznikami czasu. Kliknięcie łącza na liście powoduje wyświetlenie tego komunikatu w przeglądarce (nieprzetworzone):Ustawienia
EMAIL_BACKEND = "django.core.mail.backends.filebased.EmailBackend" EMAIL_FILE_PATH = f"{MEDIA_ROOT}/email_out"
Widok
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})
Szablon
{% 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 %}
adresy URL
path("mailcheck/", view=mailcheck, name="mailcheck"),
źródło
Dlaczego nie uruchomić własnego, naprawdę prostego serwera SMTP, dziedzicząc po
smtpd.SMTPServer
ithreading.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()
komunikat_procesu jest wywoływany za każdym razem, gdy serwer SMTP otrzyma żądanie poczty, możesz tam robić, co chcesz.
W kodzie testowym zrób coś takiego:
smtp_server = TestingSMTPServer() smtp_server.start() do_thing_that_would_send_a_mail() smtp_server.close() self.assertIn(b'hello', smtp_server.received_data)
Wystarczy pamiętać, aby dzwoniąc do końca pętli asyncore (zatrzymać serwer ze słuchania).
close()
asyncore.dispatcher
smtp_server.close()
źródło
Jeśli masz dostępny serwer TomCat lub inny silnik serwletów, dobrym podejściem jest „Post Hoc”, który jest małym serwerem, który wygląda dla aplikacji dokładnie tak, jak serwer SMTP, ale zawiera interfejs użytkownika, który umożliwia przeglądanie i sprawdź wysłane wiadomości e-mail. Jest open source i jest ogólnie dostępny.
Znajdziesz go na: Post Hoc GitHub Site
Zobacz wpis na blogu: PostHoc: Testowanie aplikacji, które wysyłają e-maile
źródło