求助:Django单元测试中mock.patch对顶部导入函数失效
问题:Django单元测试中mock.patch对顶部导入的外部函数失效
我有一个对接外部服务的Django应用,编写单元测试时需要用mock.patch打桩调用外部服务的函数,但顶部导入外部函数时patch无法生效,只有把导入放到方法内部才正常。
代码示例:
原api_views.py(patch失效)
#api_views.py from examplemodule import examplefunction class GetSomeInfoFromExternalService(ApiView): def get(self, *args, **kwargs): if examplefunction(attrs) == somevalue: return Response({'detail':'OK'}) return Response({'detail':'Not ok'})
原tests.py
#tests.py from unittest import mock # 注:原代码拼写错误,应为unittest而非unittests,pach应为patch from django.test import TestCase class MyTestCase(TestCase): @mock.patch('examplemodule.examplefunction') def test_1(self, mock_func): mock_func.return_value=123 # 此处需补充执行请求测试的代码
修改后可正常工作的api_views.py
#api_views.py class GetSomeInfoFromExternalService(ApiView): def get(self, *args, **kwargs): from examplemodule import examplefunction if examplefunction(attrs) == somevalue: return Response({'detail':'OK'}) return Response({'detail':'Not ok'})
请问该如何解决顶部导入时mock.patch失效的问题?
解决方案
核心原因
mock.patch的作用是替换目标模块中引用的对象,而非原模块里的原始对象。当你在api_views.py顶部导入examplefunction时,api_views模块会直接持有原函数的引用。此时你patchexamplemodule.examplefunction,只会修改原模块的引用,不会影响api_views里已经加载好的那个函数引用。
正确做法:patch目标模块中的引用路径
把patch的目标路径改成api_views.examplefunction,也就是api_views模块中实际使用的那个函数引用,而非原模块的路径。
修正后的tests.py代码:
#tests.py from unittest import mock from django.test import TestCase from django.urls import reverse from rest_framework.test import APIClient class MyTestCase(TestCase): def setUp(self): self.client = APIClient() @mock.patch('api_views.examplefunction') # 改为api_views中的引用路径 def test_1(self, mock_example_func): # 设置mock返回值 mock_example_func.return_value = 123 # 发起请求测试 url = reverse('your-api-url-name') # 替换为你的API路由名称 response = self.client.get(url) # 断言结果 self.assertEqual(response.status_code, 200) self.assertEqual(response.data['detail'], 'OK')
额外注意事项
- 原代码里的
from unittests import mock是拼写错误,正确应为from unittest import mock mock.pach是拼写错误,正确应为mock.patch- 测试方法需要接收mock对象作为参数(如上述代码中的
mock_example_func),才能设置返回值 - 测试中需实际发起API请求,才能触发mock的调用
内容的提问来源于stack exchange,提问作者ThunderHorn
相关产品推荐
相关产品推荐

