pytest-django
pytest-django copied to clipboard
`mail.outbox` not being set?
Hey there, thanks for pytest-django! Appreciate all of the hard work, have used it quite a few times with no problems.
We're running into a bit of a snag where we upgraded some things and suddenly mail.outbox
isn't retaining emails during tests. I've tried to figure out how exactly to use the mailoutbox
fixture as documented here but I am having trouble using this.
Right now we're testing in a class and I have tried quite a few configurations to pass mailoutbox
fixture. I.e. I updated the ini:
[pytest]
usefixtures = mailoutbox
Not exactly sure how to use that fixture though, I tried adding the positional argument mailoutbox
to my class methods, still not able to access it.. I am sure I am missing something simple.
Would appreciate a push in the right direction -- and again, thanks so much for this project!
See https://github.com/pytest-dev/pytest-django/blob/5da0935731d71aa347c57cd1753f51e3ba9f32d5/docs/helpers.rst#clearing-of-mailoutbox (7aee367). (Not clear if I understand the issue correctly though)
I think I'm having the same issue, so I decided to strip down my test to a basic email sending and ran it individually:
def test_reset_password(mailoutbox, db, settings):
text_message = render_to_string('emails/password_reset/password_reset_successful.txt',
context={})
html_message = render_to_string('emails/password_reset/password_reset_successful.html',
context={})
subject = render_to_string('emails/password_reset/password_reset_successful_subject.txt',
context={})
email = EmailMultiAlternatives(
subject=subject,
body=text_message,
from_email="[email protected]",
to=['[email protected]']
)
if html_message:
email.attach_alternative(html_message, "text/html")
email.send()
print(settings.EMAIL_BACKEND)
assert len(mailoutbox) == 1
> assert len(mailoutbox) == 1
E assert 0 == 1
E + where 0 = len([])
accounts/tests/api/test_reset_password.py:200: AssertionError
----------------------------------------------- Captured stdout call ------------------------------------------------
django.core.mail.backends.locmem.EmailBackend
--------------------------------------------- Captured stdout teardown ----------------------------------------------
Now the cool part is if I remove the db
fixture, the test passes. So I tried deleting my django_db_setup
method, but to no avail...
I'm stuck at the moment.
I forgot to mention there are some tests, in the same project, where the mailoutbox
fixture seems to work, so I tried to spot any difference between those tests and the one that fails.
The only difference I found is the positioning of the mailoutbox
argument in the test function. If it's before any fixture that depends on the db
fixture it doesn't work, but it works if I put it after, so I guess I found a workaround.
I can confirm we are seeing this behaviour too with pytest-django==3.3.3
@bogdanpetrea Thanks for the investigation / update. Will be helpful for somebody debugging/fixing this.
Not sure if it is realy related, but I've found that there might be an AttributeError due to mail.outbox
not being set in the first place - but this is related to changing the environment while pytest-django spins up.
Ref: https://github.com/pytest-dev/pytest-django/pull/708
I have currently the problem, that mailoutbox is not empty :( It's the latest test function argument.
EDIT: I call mailoutbox.clear()
before real test code as work-a-round.
@jedie Can you provide a reproducible test case? A failing test for pytest-django would be the best, of course.
Related to #708? (i.e. poke around the code that it touches there)
I've created a trivial test case that reproduces the issue (at least the way I'm experiencing it): https://github.com/pytest-dev/pytest-django/compare/master...koniiiik:589-mailoutbox-is-not-django-core-mail-outbox?expand=1
From how I've used mailoutbox
, it would also be very helpful to be able to have mailoutbox.clear()
actually clear both mailoutbox
and mail.outbox
. If mailoutbox is mail.outbox
, then someone could clear the outbox before running code that is then supposed to generate a specific number of emails (I.E. say 1
email).
Not sure if this is related to this issue, but the mailoutbox
fixture does not match the behavior of mail.outbox
in my test. It's not collecting sent emails:
(Pdb) mail.outbox
[<django.core.mail.message.EmailMultiAlternatives object at 0x7f6d864cb198>]
(Pdb) mailoutbox
[]
(Pdb)
Not sure if this is related to this issue, but the
mailoutbox
fixture does not match the behavior ofmail.outbox
in my test. It's not collecting sent emails:(Pdb) mail.outbox [<django.core.mail.message.EmailMultiAlternatives object at 0x7f6d864cb198>] (Pdb) mailoutbox [] (Pdb)
Same.
mail.outbox
contains a message while mailoutbox
is empty.
pytest-django version is 3.9.0.
I have the same issue.
If I use the fixture like this it fails:
def test_send_foo_mail(mailoutbox, user_client, foo):
Like this it works:
def test_send_foo_mail(user_client, foo, mailoutbox):
It took me a lot of time to discover it. I would like to help to debug this. I looked at the implementation, but I don't have a clue how to debug this.
Related: https://stackoverflow.com/questions/66846621/mailoutbox-works-only-if-last-fixture
Experiencing the same behavior as previous commentator. Using it like this doesn't work:
def test_command_and_email(
mailoutbox, argument, time_machine, mocker
):
But everything works as exected if I just put it at the last place.
def test_command_and_email(
argument, time_machine, mocker, mailoutbox
):
Argument argument
is also a fixture that uses db
fixture, so I guess that's the main reason of this behavior.
I'm using pytets-django 4.3.0