Skip to content

Commit

Permalink
Adding mailoutbox fixture, and removing internal _django_clear_outbox (
Browse files Browse the repository at this point in the history
  • Loading branch information
peterlauri authored and timb07 committed May 26, 2018
1 parent cbc1273 commit 1537f40
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 16 deletions.
17 changes: 17 additions & 0 deletions docs/changelog.rst
@@ -1,6 +1,23 @@
Changelog
=========

3.1.0
-----

Features
^^^^^^^^
* Added new function scoped fixture ``mailoutbox`` that gives access to
djangos ``mail.outbox``. The will clean/empty the ``mail.outbox`` to
assure that no old mails are still in the outbox.

Compatibility
^^^^^^^^^^^^^
* IMPORTANT: the internal autouse fixture _django_clear_outbox has been
removed. If you have relied on this to get an empty outbox for your
test, you should change tests to use the ``mailoutbox`` fixture instead.
See documentation of ``mailoutbox`` fixture for usage. If you try to
access mail.outbox directly, AssertionError will be raised.

3.0.0
-----

Expand Down
22 changes: 22 additions & 0 deletions docs/helpers.rst
Expand Up @@ -243,3 +243,25 @@ Example
def test_with_specific_settings(settings):
settings.USE_TZ = True
assert settings.USE_TZ

``mailoutbox``
~~~~~~~~~~~~~~~~~~~~~~~~~

A clean mail outbox where django emails are being sent.

Example
"""""""

::

from django.core import mail

def test_mail(mailoutbox):
mail.send_mail('subject', 'body', 'from@example.com', ['to@example.com'])
assert len(mailoutbox) == 1
m = mailoutbox[0]
assert m.subject == 'subject'
assert m.body == 'body'
assert m.from_email == 'from@example.com'
assert list(m.to) == ['to@example.com']

36 changes: 30 additions & 6 deletions pytest_django/plugin.py
Expand Up @@ -445,12 +445,36 @@ def teardown():
request.addfinalizer(teardown)


@pytest.fixture(autouse=True, scope='function')
def _django_clear_outbox(django_test_environment):
"""Clear the django outbox, internal to pytest-django."""
if django_settings_is_configured():
from django.core import mail
del mail.outbox[:]
class _DirectMailboxAccessProtector(list):

def _raise_assertion(*args, **kwargs):
raise AssertionError('To access mail.outbox, use the mailoutbox fixture.')

__len__ = __getitem__ = __nonzero__ = __bool__ = _raise_assertion


@pytest.fixture(autouse=True)
def _error_on_direct_mail_outbox_access(monkeypatch):
if not django_settings_is_configured():
return

from django.core import mail

outbox = _DirectMailboxAccessProtector()
monkeypatch.setattr(mail, 'outbox', outbox)
return outbox


@pytest.fixture(scope='function')
def mailoutbox(monkeypatch, _error_on_direct_mail_outbox_access):
if not django_settings_is_configured():
return

from django.core import mail

outbox = list()
monkeypatch.setattr(mail, 'outbox', outbox)
return outbox


@pytest.fixture(autouse=True, scope='function')
Expand Down
36 changes: 26 additions & 10 deletions tests/test_environment.py
Expand Up @@ -5,6 +5,7 @@
import pytest
from django.core import mail
from django.db import connection
from django.test import TestCase

from pytest_django_test.app.models import Item

Expand All @@ -15,19 +16,34 @@
# to do it.


def test_mail():
assert len(mail.outbox) == 0
def test_direct_mailbox_access_not_allowed():
with pytest.raises(AssertionError):
len(mail.outbox)

with pytest.raises(AssertionError):
mail.outbox[0]

with pytest.raises(AssertionError):
if mail.outbox:
pass


def test_direct_mailbox_proection_should_not_break_sending_mail():
mail.send_mail('subject', 'body', 'from@example.com', ['to@example.com'])
assert len(mail.outbox) == 1
m = mail.outbox[0]
assert m.subject == 'subject'
assert m.body == 'body'
assert m.from_email == 'from@example.com'
assert list(m.to) == ['to@example.com']


def test_mail_again():
test_mail()
class TestDirectAccessWorksForDjangoTestCase(TestCase):

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

def test_one(self):
self._do_test()

def test_two(self):
self._do_test()


@pytest.mark.django_project(extra_settings="""
Expand Down
17 changes: 17 additions & 0 deletions tests/test_fixtures.py
Expand Up @@ -10,6 +10,7 @@

from django.db import connection
from django.conf import settings as real_settings
from django.core import mail
from django.test.client import Client, RequestFactory
from django.test.testcases import connections_support_transactions
from django.utils.encoding import force_text
Expand Down Expand Up @@ -403,3 +404,19 @@ def test_unblock_manually(self, django_db_blocker):
def test_unblock_with_block(self, django_db_blocker):
with django_db_blocker.unblock():
Item.objects.exists()


def test_mail(mailoutbox):
assert mailoutbox is mail.outbox # check that mail.outbox and fixture value is same object
assert len(mailoutbox) == 0
mail.send_mail('subject', 'body', 'from@example.com', ['to@example.com'])
assert len(mailoutbox) == 1
m = mailoutbox[0]
assert m.subject == 'subject'
assert m.body == 'body'
assert m.from_email == 'from@example.com'
assert list(m.to) == ['to@example.com']


def test_mail_again(mailoutbox):
test_mail(mailoutbox)

0 comments on commit 1537f40

Please sign in to comment.