Django单元测试中如何mock类视图挂载的自定义装饰器?
单元测试中Mock类视图方法装饰器的解决方案
核心逻辑:装饰器会在模块导入阶段就绑定到目标方法上,因此mock动作必须发生在视图模块导入前,或直接调用未被装饰的原始方法。
方案1:提前mock装饰器(推荐,适合全局批量处理)
该方案通过提前mock装饰器使其直接返回原函数,相当于装饰器完全不生效,后续导入的视图类不会被挂载认证逻辑:
from unittest.mock import patch # 第一步:先mock装饰器,再导入视图模块 # 替换路径为你项目中authentication_decorator在视图里的引用路径 patch("your_app.views.authentication_decorator", side_effect=lambda func: func).start() # 第二步:mock完成后再导入视图和依赖 from your_app.views import AddBlogView from rest_framework.test import APITestCase class AddBlogViewTest(APITestCase): def test_create_blog_success(self): # 正常编写业务测试逻辑即可 test_data = {"title": "测试博客", "content": "测试内容"} response = self.client.post("/api/add_blog/", test_data, format="json") self.assertEqual(response.status_code, 201)
注意patch路径遵循「在哪里使用就在哪里patch」原则:如果你的视图文件是从
common.decorators导入authentication_decorator,就需要patch视图模块内引用的这个装饰器,而不是直接patchcommon.decorators.authentication_decorator。
方案2:直接调用原始未装饰方法(适合单个测试用例临时绕过)
Python的装饰器默认会给原函数添加__wrapped__属性,存储未被装饰的原始函数,你可以在测试时直接替换视图类的post方法为原始方法:
from rest_framework.test import APITestCase from your_app.views import AddBlogView class AddBlogViewTest(APITestCase): def setUp(self): # 保存原方法,测试结束后恢复 self.original_post = AddBlogView.post # 替换为未被装饰的原始方法 AddBlogView.post = lambda self, request, *args, **kwargs: self.original_post.__wrapped__(self, request, *args, **kwargs) def tearDown(self): # 恢复原方法,避免影响其他测试用例 AddBlogView.post = self.original_post def test_create_blog_success(self): test_data = {"title": "测试博客", "content": "测试内容"} response = self.client.post("/api/add_blog/", test_data, format="json") self.assertEqual(response.status_code, 201)
额外说明
- 若使用pytest框架,可以把提前mock装饰器的逻辑写到
conftest.py的会话级fixture中,全局生效无需重复编写。 - 若需要保留装饰器但仅mock内部的HTTP请求逻辑,可以直接patch装饰器内部发送HTTP请求的方法,无需跳过整个装饰器。
内容的提问来源于stack exchange,提问作者Avik Pradhan
相关产品推荐
相关产品推荐

