Django+pytest测试Celery任务:如何确保邮件通知任务同步执行?
问题分析与解决方案
首先你的代码存在一个明显笔误:load_rawdata_on_monday里调用的是notify_report_was_not_updated.delay(),但定义的任务却是notify_rawdata_was_not_updated,这会导致任务无法正确触发,先把这个错误修正。
测试用例失效的核心原因及修正方案如下:
核心问题
- 异步执行导致邮件未即时生成:你设置了
CELERY_ALWAYS_EAGER=False,这会让Celery以异步模式运行,delay()调用的任务会被放入队列而非立刻执行,测试时邮件还未发送,mail.outbox自然为空。 - 邮件后端配置错误:你写的
memcache.EmailBackend是错误的,Django测试专用的内存邮件后端是locmem.EmailBackend,只有它会把邮件暂存到mail.outbox供校验。 - Patch路径不正确:你需要patch任务所在模块的
load_rawdata函数,而非直接patch函数名(若测试文件与任务文件不在同一模块)。
修正后的测试用例
假设你的Celery任务都在myapp.tasks模块下,测试代码应修改为:
from django.core import mail from django.test import override_settings, patch from unittest.mock import MagicMock from myapp.tasks import load_rawdata_on_monday @override_settings(EMAIL_BACKEND='django.core.mail.backends.locmem.EmailBackend') @override_settings(CELERY_ALWAYS_EAGER=True) @patch('myapp.tasks.load_rawdata', MagicMock(return_value=False)) def test_load_rawdata_on_monday(): # 执行任务 load_rawdata_on_monday() # 校验邮件内容 assert len(mail.outbox) == 1, "邮件未发送" assert mail.outbox[0].subject == 'Subject here' assert mail.outbox[0].body == 'Here is the message.' assert mail.outbox[0].from_email == 'from@example.com' assert mail.outbox[0].to == ['to@example.com']
关键修正说明
CELERY_ALWAYS_EAGER=True:强制Celery同步执行任务,delay()调用会立刻执行任务函数,无需等待worker处理。- 修正邮件后端:使用
locmem.EmailBackend确保邮件被暂存到mail.outbox,方便测试校验。 - 正确Patch目标:Patch任务模块内的
load_rawdata引用,确保load_rawdata_on_monday调用的是Mock后的函数。 - 修正任务调用名:将
notify_report_was_not_updated.delay()改为notify_rawdata_was_not_updated.delay(),保证任务能被正确找到并执行。
内容的提问来源于stack exchange,提问作者Альберт Александров
相关产品推荐
相关产品推荐

