作用域选错会导致测试变慢或出错:session级适合只读/线程安全的全局资源,module级兼顾隔离与效率,function级确保上下文干净但需避免重复耗时操作。

fixture 作用域选错,测试就变慢还出错
选 scope='session' 却在函数里改了全局状态,下个测试就崩;选 scope='function' 却反复连数据库,跑 100 个测试等 3 分钟——作用域不是“越大越好”,得看它管什么、谁用它、能不能共享。
哪些资源该用 scope='session'
适合整个测试会话只初始化一次、且全程只读或线程安全的资源。比如配置加载、远程 API 的 mock server 启动、编译好的测试工具二进制文件路径。
-
scope='session'的 fixture 只执行一次,所有测试模块共享同一个返回值,不能依赖测试函数内部的参数或临时目录 - 如果 fixture 内部调用了
tempfile.mkdtemp()或修改了os.environ,别用 session 级,否则后续测试可能读到残留路径或脏环境变量 - pytest 本身不保证 session 级 fixture 在多进程(
-n auto)下安全,真要用,得加锁或改用scope='package'+ 显式初始化控制
scope='module' 是最常被低估的中间态
模块级 fixture 在一个 .py 文件内所有测试函数共享,既避免重复开销,又天然隔离不同文件间的副作用。比 session 安全,比 function 高效。
- 典型场景:每个测试文件单独建一个 SQLite 内存数据库、预载一组固定测试数据、启动一个仅本模块用的 Flask 测试 client
- 注意:模块内若用
importlib.reload()或动态 patch 某个模块,scope='module'fixture 可能因缓存导致行为不一致 - 如果两个测试文件 import 了同一份 fixture 函数但没声明
autouse=True,它们不会共享实例——scope 是按“调用位置”而非“函数定义”生效的
为什么 scope='function' 不是默认就一定慢
function 级看似低效,但它是唯一能干净隔离每个测试上下文的方式。很多“慢”其实来自 fixture 内部没做轻量初始化,比如每次都重连 Redis 而不是复用连接池。
立即学习“Python免费学习笔记(深入)”;
- 检查 fixture 是否在每次调用都做了耗时操作:打开文件、发起 HTTP 请求、执行 SQL
CREATE TABLE—— 这些该提到 module 或 session 级 - 若必须 function 级,优先返回已构造好的对象(如
Mock()实例),而不是每次 new 一个新类实例再 set 属性 - pytest 会缓存 function 级 fixture 的返回值直到当前测试函数结束,所以同个测试里多次 request 同个 fixture 不会重复执行,这点常被忽略
真正卡住效率的往往不是 scope 本身,而是 fixture 里混进了不该它管的事:比如在 session 级 fixture 里写日志到固定文件,结果所有测试往同一个句柄狂写;或者 module 级 fixture 返回了一个没 close 的 socket,下一个测试一读就 timeout。scope 是边界,不是保险箱。










