Python使用Mock库做单元测试触发ModuleNotFoundError问题求助
问题原因及解决方案
1. ModuleNotFoundError 报错原因
你当前在tests目录下直接执行测试文件,Python 默认只会将当前工作目录(也就是/path/to/artwork_grabber/tests)加入模块搜索路径,上层的项目根目录不在搜索路径里,所以找不到内层的artwork_grabber包。
对应解决方法(任选其一即可)
- 方法1:切换工作目录到最外层的
artwork_grabber项目根目录,使用模块方式运行测试:
这种方式会自动将当前根目录加入Python的模块搜索路径,可正常识别包。python -m unittest tests/test_module.py - 方法2:在测试文件开头手动添加项目根目录到搜索路径,在
test_module.py最顶部加入以下代码:import sys from pathlib import Path # 将当前文件的父目录的父目录(也就是项目根目录)加入搜索路径 sys.path.append(str(Path(__file__).parent.parent.resolve())) - 方法3:将项目配置为可安装包,在项目根目录新增
pyproject.toml配置文件后执行pip install -e .,将包安装到当前Python环境中,可全局导入。
2. 测试代码本身的逻辑错误
解决导入问题后你还会遇到Mock使用错误的问题,当前测试写法有三个明显问题:
- 你导入的是
from mock import patch,但装饰器写的是@mock.patch,缺失mock的导入,要么把装饰器改为@patch,要么新增import mock的导入语句。 - 你Patch的是要测试的
create_search_term函数本身,相当于直接把待测逻辑替换成了假的返回值,完全无法测试真实的函数逻辑。正确做法是Patch函数依赖的两个外部调用:os.path.isfile和TinyTag.get。 - 原函数逻辑里存在错误:
if str(path.isfile(file_path_to_song)):这行代码会把布尔值转为非空字符串,不管文件是否存在判断都会为真,应该改为if path.isfile(file_path_to_song):。
修正后的测试代码示例
from unittest import TestCase from mock import patch import unittest # 导入模块后可以直接用模块名访问内部对象 import artwork_grabber.helpers as helpers class UnitTests(TestCase): mock_song_info = { "album": "A Deeper Understanding", "artist": "The War On Drugs" } # 同时mock两个依赖对象,注意装饰器参数顺序和函数参数顺序是反过来的 @patch('artwork_grabber.helpers.path.isfile') @patch('artwork_grabber.helpers.TinyTag.get') def test_create_search_term(self, mock_tinytag_get, mock_isfile): # 配置mock的返回值 mock_isfile.return_value = True mock_tag = mock_tinytag_get.return_value mock_tag.get_album.return_value = self.mock_song_info["album"] mock_tag.get_artist.return_value = self.mock_song_info["artist"] actual_result = helpers.create_search_term("fake/path/to/song.mp3") expected_result = "The War On Drugs A Deeper Understanding Album Cover" self.assertEqual(actual_result, expected_result, "Expected the search terms to match.") if __name__ == "__main__": unittest.main()
内容的提问来源于stack exchange,提问作者mgermaine93
相关产品推荐
相关产品推荐

