为什么这个 Django 测试会通过?

3

独立调用send_mail函数会由于主题中的换行符而导致BadHeaderError异常。

我预计test_newline_causes_exception也会失败,但它并没有。 这是在Django 1.3中发生的。 有什么想法吗?

from django.core.mail import send_mail
from django.utils import unittest

class EmailTestCase(unittest.TestCase):

    def test_newline_causes_exception(self):
        send_mail('Header\nInjection', 'Here is the message.', 'from@example.com',
                  ['to@example.com'], fail_silently=False)

编辑:这个新的测试显示,当在测试中使用send_mail时,头部检查代码(django.core.mail.message.forbid_multi_line_headers)不会被调用。

from django.core.mail import send_mail, BadHeaderError, outbox
from django.utils import unittest

class EmailTestCase(unittest.TestCase):

    def test_newline_in_subject_should_raise_exception(self):

        try:
            send_mail('Subject\nhere', 'Here is the message.',
                      'from@example.com', ['to@example.com'], fail_silently=False)
        except BadHeaderError:
            raise Exception

        self.assertEqual(len(outbox), 1)

        self.assertEqual(outbox[0].subject, 'Subject here')

结果:

AssertionError: 'Subject\nhere' != 'Subject here'

在 Django shell 中会抛出异常吗? - alecxe
@AlexanderAfanasiev 是的。 - Alex
3
在测试阶段,Django会用测试邮件后端替换正常的邮件后端,这可能是导致问题的原因。请检查django.core.mail.outbox中是否有邮件,或者换句话说,是否实际发送了消息。请参阅 https://docs.djangoproject.com/en/1.3/topics/testing/#e-mail-services。 - alecxe
可能这就是原因。消息以某种方式到达了。请查看我对代码的编辑。 - Alex
发现一个相关问题:https://dev59.com/OXzfs4cB2Jgan1zn0jKI - Alex
显示剩余2条评论
2个回答

3

你并没有真正进行测试。测试意味着检查是否已经引发了BadHeaderError。如果断言测试失败,则测试将失败。你可以像这样做 -

def test_newline_causes_exception(self)
    error_occured = False
    try:
        send_mail('Header\nInjection', 'Here is the message.', 'from@example.com',
                  ['to@example.com'], fail_silently=False)
    except BadHeaderError:
        error_occured = True

    self.assertTrue(error_ocurred)

我还没有进行测试,但应该可以工作。
PS:from django.core.mail import send_mail, BadHeaderError

谢谢。我明白你的意思,但是我写的测试仍然应该失败,对吗?就像如果我包括一行“raise Exception”一样,它也会失败。 - Alex
也许,我不确定你是如何实现它的。可能有很多其他条件会影响它(例如邮件传递延迟等)。我只知道,如果你想检查是否引发了“BadHeaderError”,你应该检查它而不是其他方式。 - Bibhas Debnath

2
我发现这个问题已经在Django 1.5中得到解决了。测试邮件后端(locmem.py)现在执行与标准后端相同的标题清理。

https://code.djangoproject.com/ticket/18861

https://github.com/django/django/commit/8599f64e54adfb32ee6550ed7a6ec9944034d978

编辑

我找到了一种解决方案,可以在Django版本<1.5中测试标题验证。

使用get_connection方法加载控制台后端,该后端执行与生产后端相同的验证。

感谢Alexander Afanasiev指导我正确的方向。

connection = get_connection('django.core.mail.backends.console.EmailBackend')
send_mail('Subject\nhere',
          'Here is the message.',
          'from@example.com',
          ['to@example.com'],
          fail_silently=False,
          connection=connection)

1
那么,对于django<1.5的版本,解决方法是模拟django.core.mail.backends.locmem.EmailBackend.send_messages方法,并为每个消息调用message.message(),对吗?那么我认为这应该被接受为您问题的答案。 - alecxe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接