Django/DRF测试Mock Shell脚本方法报AttributeError问题求助
问题:Mock Django视图依赖的外部脚本方法时出现AttributeError
问题背景
测试Django/DRF视图方法时,该方法会调用一个仅适配其他操作系统的Shell脚本,需要Mock对应的Python函数,但运行测试时触发AttributeError,提示check_web_share_file_folder函数没有get_path_from_inode属性,实际该函数存在于对应文件中。
项目结构
django/ ├── webshare/ │ ├── actions │ │ └── check_web_share_file_folder.py │ ├──────── │ └── tests │ └── factories │ └── test_web_share_file_folder_view.py
测试代码
@patch('check_web_share_file_folder.get_path_from_inode') def test_list_with_search_mocked(self, mock_get_attribute): mock_get_attribute.return_value = 'expected value' request = self.factory.get('/fake-url') force_authenticate(request, user=self.user) view = WebShareFileFolderViewSet.as_view({'get': 'list'}) response = view(request) self.assertEqual(response.status_code, status.HTTP_200_OK)
报错信息
AttributeError: <function check_web_share_file_folder at 0x00000237FD567708> does not have the attribute 'get_path_from_inode'
目标函数(check_web_share_file_folder.py中)
def get_path_from_inode(inode): std, err, code = popen_wrapper([ 'sudo', 'get_path_from_inode.sh', str(inode) ]) if code != 0: return False return str(std.strip())[1:]
解决方案
问题根源是Mock路径不正确。当前使用的@patch('check_web_share_file_folder.get_path_from_inode')是相对路径,Python误将check_web_share_file_folder识别为某个函数而非模块,因此找不到get_path_from_inode属性。
正确的Mock路径
根据项目结构,必须使用完整的模块导入路径:
@patch('webshare.actions.check_web_share_file_folder.get_path_from_inode')
原理说明
Mock的核心规则是:Mock被测试代码实际导入的路径,而非目标函数所在的原始文件路径。假设你的视图代码中是这样导入目标函数的:
from webshare.actions.check_web_share_file_folder import get_path_from_inode
或者
import webshare.actions.check_web_share_file_folder as check_module # 调用时用 check_module.get_path_from_inode(...)
那么Mock时必须严格匹配这个导入路径,否则Python会定位到错误的对象,导致属性查找失败。
修改后的完整测试代码示例
from unittest.mock import patch from rest_framework import status from rest_framework.test import force_authenticate, APITestCase from webshare.views import WebShareFileFolderViewSet class WebShareFileFolderViewTest(APITestCase): def setUp(self): self.user = # 初始化测试用户对象 self.factory = # 初始化请求工厂 @patch('webshare.actions.check_web_share_file_folder.get_path_from_inode') def test_list_with_search_mocked(self, mock_get_path): mock_get_path.return_value = 'expected value' request = self.factory.get('/fake-url') force_authenticate(request, user=self.user) view = WebShareFileFolderViewSet.as_view({'get': 'list'}) response = view(request) self.assertEqual(response.status_code, status.HTTP_200_OK)
内容的提问来源于stack exchange,提问作者jordan
相关产品推荐
相关产品推荐

