单元测试中跳过Django视图的发邮件函数与Celery任务
解决Django视图单元测试中Celery邮件任务停滞+Mock失效的问题
我之前踩过一模一样的坑!你遇到的核心问题绝对是patch的路径不对——Python的Mock是基于「导入引用」生效的,不是看函数定义在哪里,而是看调用它的代码是从哪个路径导入的。
问题根源拆解
举个例子,假设你的代码结构是这样的:
your_project/ ├── app/ │ ├── views.py # 里面的view_function调用了function_a │ ├── helpers.py # 里面的function_a从.emails导入了send_email_function │ └── emails.py # 里面的send_email_function调用celery_task.delay()
当helpers.py执行from .emails import send_email_function时,会在自己的模块空间里创建一个send_email_function的引用。如果你patch的是app.emails.send_email_function,只会修改原模块里的函数,不会影响helpers.py里已经导入的那个引用——所以测试时还是会执行真实的函数,导致Celery任务卡住。
正确的解决步骤
确定正确的patch路径:你需要patch的是function_a所在模块中导入的send_email_function,也就是上面例子里的
app.helpers.send_email_function,而非app.emails.send_email_function。修正测试代码:
下面是结合DRF API Request Factory的完整测试示例:
from django.test import TestCase from rest_framework.test import APIRequestFactory from your_project.app.views import view_function from unittest.mock import patch class ViewFunctionTestCase(TestCase): def setUp(self): self.factory = APIRequestFactory() # 重点:这里的路径是function_a所在模块导入send_email_function的路径 @patch('your_project.app.helpers.send_email_function') def test_view_function(self, mock_send_email): # 配置Mock的行为 mock_send_email.return_value = None # 构造请求并触发视图 request = self.factory.post('/your-view-endpoint/', data={"key": "value"}) response = view_function(request) # 验证视图响应是否符合预期 self.assertEqual(response.status_code, 200) # 验证邮件函数确实被调用(可选) mock_send_email.assert_called_once()
- 额外优化:Celery测试配置(可选)
如果不想完全Mock邮件函数,而是让Celery任务同步执行避免卡住,可以在测试环境的settings.py中添加:
CELERY_TASK_ALWAYS_EAGER = True CELERY_TASK_EAGER_PROPAGATES = True
这样Celery会直接同步执行任务,不会放到异步队列里,测试就不会停滞了。
最后再确认
你只需要把@patch里的路径改成调用send_email_function的模块(即function_a所在模块)里的导入路径,Mock就会生效,测试也不会因为Celery任务卡住了!
内容的提问来源于stack exchange,提问作者Hamed Fathi
相关产品推荐
相关产品推荐

