Phillip Ahereza asks:
I’m writing unit tests for my django app and I was wondering if there are any packages for mocking email or if there is any way I could mock sending and receiving of emails.
Answer
Basically what Django does when you run your test suite is switch your EMAIL_BACKEND
to
django.core.mail.backends.locmem.EmailBackend
, so to prevent your application from sending emails during the tests
execution.
While using this backend, all emails sent are stored in the outbox
attribute of the django.core.mail
module.
Let’s see one example on how you can use it to test the email outputs and so on.
urls.py
from django.conf.urls import url
from mysite.core import views
urlpatterns = [
url(r'^send/$', views.send, name='send'),
]
views.py
from django.http import HttpResponse
from django.core.mail import send_mail
def send(request):
email = request.GET.get('email')
if email and '@' in email:
body = 'This is a test message sent to {}.'.format(email)
send_mail('Hello', body, 'noreply@mysite.com', [email, ])
return HttpResponse('<h1>Sent.</h1>')
else:
return HttpResponse('<h1>No email was sent.</h1>')
This is a simple view that expects a querystring parameter named email
with a valid email address. If the email value
fulfill our view requirements, an email is sent to this address. If the email is invalid or no email is provided at
all, the view just return a message for the user.
Now, let’s write some unit tests for it. First, a test case in case no email is provided:
tests.py
from django.core import mail
from django.core.urlresolvers import reverse
from django.test import TestCase
class EmailTest(TestCase):
def test_no_email_sent(self):
self.response = self.client.get(reverse('send'))
self.assertEqual(len(mail.outbox), 0)
We can also write a test case and inspect the email contents:
tests.py
from django.core import mail
from django.core.urlresolvers import reverse
from django.test import TestCase
class EmailTest(TestCase):
def test_no_email_sent(self):
self.response = self.client.get(reverse('send'))
self.assertEqual(len(mail.outbox), 0)
def test_email_sent(self):
self.response = self.client.get(reverse('send'), {'email': 'test@example.com'})
self.assertEqual(len(mail.outbox), 1)
self.assertEqual(mail.outbox[0].body, 'This is a test message sent to test@example.com.')
Final Remarks
Simple as that! You can find more information about the testing tools and email services on the official documentation: Django Testing Tools - Email Services.
You can also find the source code used in this post on Github: github.com/sibtc/askvitor.