Django - 使用发件箱测试电子邮件 post_office

Django - testing emails with the outbox using post_office

我正在为使用 django-post_office 包来实现大部分电子邮件功能的应用程序编写测试。

默认的 django.core.mail 库包含大量有用的工具,用于测试是否实际发送了电子邮件。 (在测试期间实际上没有发送任何内容)

class TestFunctionThatSendsEmail(Testcase):

   @override_settings(
        EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend'
   )
   def test_function_sends_email(self):
       self.assertEqual(len(outbox), 0)
       run_function_that_calls_email()
       self.assertEqual(len(outbox), 1)
       ...
       # other tests

但是,我们函数中的电子邮件是使用 django-post_office mail.send() 函数发送的

# priority now to make sure that they are being sent right away
mail.send(
        sender=sender,
        recipients=to,
        context=context,
        template=template_name,
        priority='now',
    )

这会导致上述测试失败,因为出于某种原因,电子邮件最终不会进入发件箱。

奇怪的是,如果我将 EMAIL_BACKEND 更改为 django.core.mail.backends.console.EmailBackend,电子邮件会显示在我的终端中,所以它正在监听 EMAIL_BACKEND 设置。

我尝试在 django-post_office github 中寻找替代方法/函数来测试此功能,但我所能找到的只是检查电子邮件是否保存到数据库并验证其状态。 (我做了并且工作了)但是 django 似乎无法检测到任何实际发送的电子邮件这一事实让我有点紧张。

有谁知道让 django-post_office 发送的电子邮件出现在发件箱中的方法,或者,如果不可能的话,有什么方法可以确保它们确实被发送了吗? (除了检查数据库)

问题是 django-post_office 将邮件后端存储在 Email 对象中:

class Email(models.Model):
    backend_alias = models.CharField(_("Backend alias"), blank=True, default='',
                                     max_length=64)

当调用 dispatch() 时,它使用此后端。

创建电子邮件时,DPO 会覆盖 create() 以从 def get_available_backends() 设置后端,后者在 settings conf.

中查找后端

这意味着使用 @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend') 不会正确设置 Email 对象中的 backend_alias

相反,您需要根据调度测试在创建对象时手动执行此操作:

def test_dispatch(self):
    """
    Ensure that email.dispatch() actually sends out the email
    """
    email = Email.objects.create(to=['to@example.com'], from_email='from@example.com',
                                 subject='Test dispatch', message='Message', backend_alias='locmem')
    email.dispatch()
    self.assertEqual(mail.outbox[0].subject, 'Test dispatch')

如果您使用 mail.send(),您可以简单地将 mail.send(backend='locmem') 作为参数传递;确保 POST_OFFICE 设置中有 locmem': 'django.core.mail.backends.locmem.EmailBackend'

我遇到了与您描述的相同的问题,并通过将 DEFAULT_PRIORITY 设置为 'now' 来修复它:

class TestFunctionThatSendsEmail(Testcase):

   @override_settings(
        POST_OFFICE={
            'BACKENDS': {'default': 'django.core.mail.backends.locmem.EmailBackend'},
            'DEFAULT_PRIORITY': 'now',
        }
   )
   def test_function_sends_email(self):
       self.assertEqual(len(outbox), 0)
       run_function_that_calls_email()
       self.assertEqual(len(outbox), 1)
       ...
       # other tests