【问题标题】:Why does Django's send_mail not work during testing?为什么测试时 Django 的 send_mail 不起作用?
【发布时间】:2013-06-18 14:22:37
【问题描述】:

我有一个应用程序可以导入多个用户电子邮件地址并为其创建帐户。为了让他们设置自己的密码,我尝试使用 django 的 PasswordResetForm(在 django.contrib.auth.forms 中)。创建用户帐户后立即调用密码重置:

def reset_password(person):
    form = PasswordResetForm({'email': person.email})
    if form.is_valid():
        form.save(from_email='myname@myserver.com')

除了包含执行此操作的单元测试之外,我没有得到任何进一步的测试:

import password_reset_module
class TestPasswordReset(TestCase):
     def setUp(self):
         p = Person(email='test@test.com')
     def test_send(self):
         password_reset_module.reset_password(p)

没有断言,现在我只想通过监控我运行的控制台来查看是否有邮件发送:

python -m smtpd -n -c DebuggingServer localhost:1025

保存表单调用 django 的 send_mail。运行测试用例时,send_mail 方法返回 1。但是,控制台中没有显示任何邮件。奇怪的是,从 django 的交互式 shell 调用 send_mail:

python manage.py shell

工作正常。邮件显示在控制台中。在浏览器中单击忘记密码链接也会发送邮件。

我也尝试过基于文件的电子邮件后端,但无济于事。 当前 settings.py 电子邮件设置:

EMAIL_USE_TLS = False
EMAIL_HOST = 'localhost'
DEFAULT_FROM_EMAIL = 'myname@myserver.com'
EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_PORT = 1025

现在想知道我在调用密码重置时是否遗漏了什么,或者手头是否存在邮件服务器配置问题?

【问题讨论】:

  • 你能提供你正在使用的单元测试吗? Django 有许多电子邮件后端,它们提供在它们自己的单元测试中使用的虚拟输出(无,到控制台等)。

标签: python django email


【解决方案1】:

您的配置被否决

在“电子邮件服务”部分中, Django testing documentation 说:

Django 的测试运行器自动重定向所有 Django 将电子邮件发送到一个虚拟的发件箱。 [...] 在测试运行期间,每封发出的电子邮件都保存在 django.core.mail.outbox。 这是所有EmailMessage 实例的简单列表 已发送。

嗯?

Django 测试运行器实际上会为您配置不同的电子邮件后端(称为locmem)。 如果您只想进行单元测试,这非常方便 (没有与实际的电子邮件服务器集成),但是 如果你不知道,那就太令人惊讶了。

(我没有使用 Django 测试运行器manage.py test, 但它无论如何都会发生,大概是因为我有 安装了pytest-django,它神奇地修改了我的py.test。)

如果您想覆盖覆盖并使用电子邮件配置 在您的settings 模块中给出,您需要重新设置的是 电子邮件后端的设置,例如像这样:

@django.test.utils.override_settings(
    EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend')
def test_send_email_with_real_SMTP(self):
   ...

【讨论】:

  • override_settings 现在在 django.test: from django.test import override_settings
  • 因此浪费了很多时间
【解决方案2】:

尝试将其转换为适当的单元测试可能是值得的,当然您可以将其作为自动化测试套件的一部分运行。对于单元测试,检查邮件是否已发送(并在需要时验证邮件内容)的最简单方法可能是使用 Django 的内置内存电子邮件后端 - 您可以简单地使用此上的 outbox 属性来获取已发送邮件列表:

https://docs.djangoproject.com/en/dev/topics/email/#in-memory-backend

这具有不需要任何基础设施设置来支持测试电子邮件发送的优点,使得断言电子邮件内容变得非常简单,并且这也应该使测试速度更快(与实际将电子邮件发送到 SMTP 相比服务器)。

希望这会有所帮助。

【讨论】:

  • 谢谢!出于某种原因,使用 locmem 无需更改任何其他内容即可工作。我会格外小心地在生产环境中测试此功能。
【解决方案3】:

据我了解,您在测试单元时正在运行以下命令。

python -m smtpd -n -c DebuggingServer localhost:1025

此命令启动一个“哑”SMTP 服务器,它接收您的电子邮件并将它们显示在终端上。尝试在不设置此 DebuggingServer 的情况下运行您的站点,看看是否发送了邮件。

这里是对docs page的引用

【讨论】:

  • 谢谢。我想我的问题不是很清楚。我想看到我的邮件由哑服务器处理,但我没有。现已编辑。
【解决方案4】:

您可以使用 pytest-django 的 mailoutbox 夹具:

一个干净的电子邮件发件箱,用于发送 Django 生成的电子邮件。

例子

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

【讨论】:

    猜你喜欢
    • 2015-03-15
    • 1970-01-01
    • 2012-07-20
    • 2016-05-23
    • 1970-01-01
    • 1970-01-01
    • 2011-10-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多