Pytest-django: `mail.outbox` n'est pas défini ?

Créé le 10 avr. 2018  ·  14Commentaires  ·  Source: pytest-dev/pytest-django

Salut, merci pour pytest-django ! Appréciez tout le travail acharné, je l'ai utilisé plusieurs fois sans aucun problème.

Nous rencontrons un petit problème où nous avons mis à jour certaines choses et tout mail.outbox coup, mailoutbox comme documenté ici, mais j'ai du mal à l'utiliser.

En ce moment, nous testons dans une classe et j'ai essayé pas mal de configurations pour passer le mailoutbox luminaire. C'est-à-dire que j'ai mis à jour l'ini :

[pytest]
usefixtures = mailoutbox

Je ne sais pas exactement comment utiliser ce luminaire, j'ai essayé d'ajouter l'argument positionnel mailoutbox à mes méthodes de classe, toujours pas en mesure d'y accéder. Je suis sûr qu'il me manque quelque chose de simple.

J'apprécierais un coup de pouce dans la bonne direction - et encore une fois, merci beaucoup pour ce projet !

bug

Commentaire le plus utile

Je pense avoir le même problème, j'ai donc décidé de réduire mon test à un envoi d'e-mail de base et de l'exécuter individuellement :

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 ----------------------------------------------

Maintenant, la partie la plus cool est que si je supprime le luminaire db , le test réussit. J'ai donc essayé de supprimer ma méthode django_db_setup , mais en vain...

Je suis bloqué en ce moment.

Tous les 14 commentaires

Voir https://github.com/pytest-dev/pytest-django/blob/5da0935731d71aa347c57cd1753f51e3ba9f32d5/docs/helpers.rst#clearing -of-mailoutbox (7aee367).
(Ce n'est pas clair si j'ai bien compris le problème)

Je pense avoir le même problème, j'ai donc décidé de réduire mon test à un envoi d'e-mail de base et de l'exécuter individuellement :

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 ----------------------------------------------

Maintenant, la partie la plus cool est que si je supprime le luminaire db , le test réussit. J'ai donc essayé de supprimer ma méthode django_db_setup , mais en vain...

Je suis bloqué en ce moment.

J'ai oublié de mentionner qu'il y a des tests, dans le même projet, où le dispositif mailoutbox semble fonctionner, alors j'ai essayé de repérer une différence entre ces tests et celui qui échoue.
La seule différence que j'ai trouvée est le positionnement de l'argument mailoutbox dans la fonction de test. Si c'est avant tout appareil qui dépend du db , cela ne fonctionne pas, mais cela fonctionne si je le mets après, donc je suppose que j'ai trouvé une solution de contournement.

Je peux confirmer que nous constatons également ce comportement avec pytest-django==3.3.3

@bogdanpetrea
Merci pour l'enquête / mise à jour.
Sera utile pour quelqu'un qui débogue/répare cela.

Je ne sais pas si c'est vraiment lié, mais j'ai trouvé qu'il pourrait y avoir une AttributeError en raison du fait que mail.outbox n'est pas défini en premier lieu - mais cela est lié au changement d'environnement pendant que pytest-django tourne.
Réf : https://github.com/pytest-dev/pytest-django/pull/708

J'ai actuellement le problème, cette boîte aux lettres n'est pas vide :(
C'est le dernier argument de la fonction de test.

EDIT : j'appelle mailoutbox.clear() avant le vrai code de test comme solution de rechange.

@jedie
Pouvez-vous fournir un cas de test reproductible ? Un test raté pour pytest-django serait le meilleur, bien sûr.

Lié au #708 ? (c'est-à-dire fouiller le code qu'il touche là)

J'ai créé un cas de test trivial qui reproduit le problème (du moins la façon dont je le vis): https://github.com/pytest-dev/pytest-django/compare/master...koniiiik :589- mailoutbox-is-not-django-core-mail-outbox?expand=1

D'après la façon dont j'ai utilisé mailoutbox , il serait également très utile de pouvoir effacer mailoutbox.clear() fois mailoutbox et mail.outbox . Si mailoutbox is mail.outbox , quelqu'un pourrait effacer la boîte d'envoi avant d'exécuter le code censé générer un nombre spécifique d'e-mails (c'est-à-dire 1 email).

Je ne sais pas si cela est lié à ce problème, mais le luminaire mailoutbox ne correspond pas au comportement de mail.outbox dans mon test. Il ne collecte pas les e-mails envoyés :

(Pdb) mail.outbox
[<django.core.mail.message.EmailMultiAlternatives object at 0x7f6d864cb198>]
(Pdb) mailoutbox
[]
(Pdb)

Je ne sais pas si cela est lié à ce problème, mais le luminaire mailoutbox ne correspond pas au comportement de mail.outbox dans mon test. Il ne collecte pas les e-mails envoyés :

(Pdb) mail.outbox
[<django.core.mail.message.EmailMultiAlternatives object at 0x7f6d864cb198>]
(Pdb) mailoutbox
[]
(Pdb)

Même.
mail.outbox contient un message alors que mailoutbox est vide.
La version de pytest-django est la 3.9.0.

J'ai le même problème.

Si j'utilise le luminaire comme celui-ci, cela échoue :

def test_send_foo_mail(mailoutbox, user_client, foo):

Comme ça ça marche :

def test_send_foo_mail(user_client, foo, mailoutbox):

Il m'a fallu beaucoup de temps pour le découvrir. Je voudrais aider à déboguer cela. J'ai regardé l'implémentation, mais je ne sais pas comment déboguer cela.

Connexes : https://stackoverflow.com/questions/66846621/mailoutbox-works-only-if-last-fixture

Expérimenter le même comportement que le commentateur précédent. L'utiliser comme ceci ne fonctionne pas :

def test_command_and_email(
    mailoutbox, argument, time_machine, mocker 
):

Mais tout fonctionne comme prévu si je le mets juste à la dernière place.

def test_command_and_email(
    argument, time_machine, mocker, mailoutbox
):

L'argument argument est également un appareil qui utilise l'appareil db , donc je suppose que c'est la principale raison de ce comportement.
J'utilise pytets-django 4.3.0

Cette page vous a été utile?
0 / 5 - 0 notes