跳转到主内容
极星编程网:以代码为星,赴技术山海!

Python如何测试文件读写权限逻辑_利用pytest的monkeypatch模拟OS报错

应优先 patch builtins.open(Python 3.4+)或 __builtin__.open(Python 2),或 os.open,用真实 PermissionError 异常,避免 patch 模块内 import 的 open;需区分 PermissionError 与 FileNotFoundError;注意 monkeypatch 作用域、缓存引用及竞态条件下的 os.access + open 联合 mock。 如何用 monkeypatch 模拟
PermissionError
触发文件写入失败 直接 patch
open
函数本身容易漏掉底层系统调用,真正可靠的方式是 mock
os.open
或
io.open
底层入口。pytest 的
monkeypatch
最适合做这种“让某次系统调用突然报错”的事。 常见错误是 patch 了模块里 import 的
open
,但被测函数实际调用的是内置
open
(比如没显式 import),结果 mock 完全不生效。 优先 patch
builtins.open
(Python 3.4+)或
__builtin__.open
(Python 2) 若逻辑走
os.open
(如用
os.O_WRONLY | os.O_CREAT
),就 patch
os.open
报错必须用真实异常类,不能只 raise 字符串——否则
except PermissionError:
捕不到
def test_write_fails_on_permission_denied(monkeypatch): def mock_open(*args, **kwargs): raise PermissionError(13, "Permission denied") monkeypatch.setattr("builtins.open", mock_open) assert not write_config("/etc/app.conf", "data") # 假设该函数内部调用 open()
读取权限测试:为什么
FileNotFoundError
不等于权限问题 用户常误以为“读不了就是没权限”,其实
FileNotFoundError
表示路径不存在,
PermissionError
才是真权限拒绝。Linux 下对目录无 x 权限、文件无 r 权限,或 Windows 下文件设为只读但代码尝试以写模式打开,才会触发后者。 测试时若只 mock
FileNotFoundError
,根本覆盖不到真实权限逻辑分支。 立即学习 “ Python免费学习笔记(深入) ”; Python 3.14.3 微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。 下载 读场景下要分别模拟:
PermissionError
(有路径但不可读)、
FileNotFoundError
(路径不存在) 注意:某些函数先
os.stat()
再 open,这时得 patch
os.stat
才能控制前置检查行为 Windows 上只读文件用
open(..., "w")
会报
PermissionError
;Linux 下需手动
chmod -r file
才能复现
monkeypatch
的作用域和清理陷阱 pytest 默认在每个 test 函数结束后自动恢复被 patch 的对象,但如果你在测试中手动调用了
monkeypatch.undo()
,或者在 fixture 里用了
scope="module"
却没管理好顺序,就可能污染后续测试。 避免在
conftest.py
的 module-scoped fixture 中做全局 patch,除非你明确需要跨 test 复用且负责清理 如果被测代码缓存了
open
引用(如
_open = open
),patch
builtins.open
无效——得 patch 那个模块里的
_open
想验证“重试逻辑”时,别只 raise 一次异常:用闭包或
itertools.count
控制第几次调用才失败
from itertools import count def test_retry_on_permission_error(monkeypatch): counter = count() def mock_open(*args, **kwargs): if next(counter) == 0: raise PermissionError("denied") return io.StringIO("ok") monkeypatch.setattr("builtins.open", mock_open)
真实环境 vs 测试:为什么不能依赖
os.access()
的返回值 很多代码会先调
os.access(path, os.W_OK)
判断可写再 open,但这在多线程/多进程下是竞态的——判断完瞬间文件权限可能就被改了。所以单元测试里 mock
os.access
返回
True
,却仍要 mock
open
报错,才能覆盖“判断通过但实际失败”的路径。
os.access
在容器或 NFS 挂载点上可能返回误导性结果,它只是建议,不是保证 测试重点应放在 open 失败后的降级处理(如写日志、fallback 到临时目录),而不是验证
os.access
是否准确 若被测函数同时用
os.access
和
open
,两个都得 patch,且顺序要匹配执行流 权限逻辑的脆弱点从来不在判断,而在“判断和操作之间的时间窗口”。测试时得把那个窗口强行撕开,塞进一个错误。

相关文章