You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Celery任务中触发SMTPException测试邮件发送?

解决Celery任务中触发SMTPException的测试问题

核心问题分析

Celery任务默认异步执行时会在独立worker进程运行,你在测试进程里的mock不会作用到worker环境,这就是普通视图函数(当前进程执行)能触发异常,但Celery任务不行的根本原因。以下是具体解决步骤:


1. 强制Celery任务同步执行(最直接的测试方式)

在测试环境的Django配置里添加:

# settings.py 测试环境专属配置
CELERY_TASK_ALWAYS_EAGER = True
CELERY_TASK_EAGER_PROPAGATES = True

这样所有Celery任务都会在当前测试进程同步执行,你的mock能直接覆盖任务里的邮件发送逻辑。

2. 精准mock任务中的邮件发送方法

不要mock全局的邮件方法,直接mock任务文件里用到的EmailMultiAlternatives.send,确保mock作用域正确。示例测试代码(基于pytest+mock):

import pytest
from unittest.mock import patch
from django.core.mail import SMTPException
from my_app.mailer.tasks import send_mail

def test_send_mail_task_smtp_exception(capsys):
    # mock任务中的send方法,抛出指定的SMTPException
    with patch('my_app.mailer.tasks.EmailMultiAlternatives.send') as mock_send:
        mock_send.side_effect = SMTPException("SMTP服务器连接失败")
        
        # 同步执行Celery任务(因配置了ALWAYS_EAGER,delay也会同步执行)
        send_mail.delay()
        
        # 验证mock是否被调用
        assert mock_send.called_once()
        
        # 捕获print输出,验证异常信息是否正确打印
        captured = capsys.readouterr()
        assert "Exception  SMTP服务器连接失败" in captured.out

3. 优化任务的异常处理(可选,便于测试和生产排查)

把任务里的print改成Celery自带的日志记录,这样测试和生产环境都能统一捕获日志:

from django.core.mail import EmailMultiAlternatives
from celery.utils.log import get_task_logger

logger = get_task_logger(__name__)

@app.task(bind=True )
def send_mail(self):
    subject, from_email, to = 'hello', 'from@example.com', 'to@example.com'
    text_content = 'This is an important message.'
    html_content = '<p>This is an <strong>important</strong> message.</p>'
    msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
    msg.attach_alternative(html_content, "text/html")
    try:
        msg.send(fail_silently=False)
    except SMTPException as exc:
        logger.error('SMTP发送失败: %s', exc)  # 用日志替代print

对应的测试可以捕获日志输出:

def test_send_mail_task_logging(caplog):
    with patch('my_app.mailer.tasks.EmailMultiAlternatives.send') as mock_send:
        mock_send.side_effect = SMTPException("连接超时")
        send_mail.delay()
        assert "SMTP发送失败: 连接超时" in caplog.text

4. 手动同步执行任务(无需修改全局配置)

如果不想修改全局Celery配置,可以用apply()方法手动同步执行任务:

result = send_mail.apply(args=(), kwargs={})
# 因为任务内部捕获了异常,所以result会标记为成功状态
assert result.successful()

内容的提问来源于stack exchange,提问作者Radial

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 08:40:35