如何用pytest-mock分别模拟两个pathlib.Path实例的exists方法,测试主文件存在但关联文件缺失的场景
如何用pytest-mock分别模拟两个pathlib.Path实例的exists方法,测试主文件存在但关联文件缺失的场景
你遇到的问题本质是:pathlib.Path的exists是类绑定的实例方法,单个Path实例的exists属性是只读的,没法直接覆盖赋值,所以直接mock实例的exists会报错。下面给你提供两种靠谱的解决思路,都是通过mock类的exists方法,同时区分不同实例的返回值:
方法一:通过side_effect根据实例判断返回值
这是最直接且健壮的方式,我们给pathlib.Path.exists的mock设置一个side_effect函数,这个函数会接收当前调用的Path实例作为第一个参数(也就是self),然后根据实例判断返回True还是False:
def test_main_file_exists_second_missing(mocker): # 定义测试用的目标文件 target_file = pathlib.Path("test.txt") # 提前计算出预期的第二个文件路径 expected_second_file = target_file.parent / f"{target_file.stem}_second{target_file.suffix}" # 定义判断逻辑:只有当实例是目标文件时返回True,其他都返回False def mock_exists(self): return self == target_file # 替换Path类的exists方法,使用我们的判断逻辑 mocker.patch("pathlib.Path.exists", side_effect=mock_exists) # 执行测试,验证抛出SecondFileError with pytest.raises(SecondFileError): check_files(target_file)
这个测试的执行流程是:
- 调用
check_files(target_file)时,先检查target_file.exists(),此时self是target_file,返回True - 生成
expected_second_file后,调用它的exists(),此时self是第二个文件实例,返回False - 触发
SecondFileError,测试通过
如果担心Path实例的__eq__判断有问题(比如相对/绝对路径差异),也可以用路径字符串来判断:
def mock_exists(self): return str(self) == str(target_file)
方法二:用MagicMock按调用顺序控制返回值(适合简单场景)
如果能确定exists方法的调用顺序,也可以用列表直接指定返回值顺序,这种方式更简洁但依赖调用顺序:
def test_main_file_exists_second_missing(mocker): target_file = pathlib.Path("test.txt") # 先mock Path.exists方法 mock_exists = mocker.patch("pathlib.Path.exists") # 设置返回顺序:第一次调用返回True(主文件),第二次返回False(关联文件) mock_exists.side_effect = [True, False] with pytest.raises(SecondFileError): check_files(target_file)
注意:这种方式仅适用于你能确保exists的调用顺序不会改变的场景,如果后续代码修改了调用逻辑,测试会直接失败,所以更推荐第一种方法。
为什么你之前的尝试失败?
- 直接给Path实例赋值
exists:Path的exists是从类继承的方法,实例的这个属性是只读的,没法直接覆盖 - patch实例的
exists属性:同样因为实例的exists是只读的,patch操作会触发AttributeError - mock
__getattr__:Path类本身没有定义__getattr__方法,所以mock这个属性也会报错
备注:内容来源于stack exchange,提问作者3dSpatialUser
相关产品推荐
相关产品推荐

