引言
在做接口自动化测试时,你可能遇到过这样的情况:
单独运行某个用例一切正常,但批量跑测试时,大量接口返回 401 或权限错误。
这通常是 fixture 生命周期与共享状态导致的问题。本文结合实际场景,带你深入理解 Pytest 的 fixture 作用域,并提供解决方案。
一、Pytest Fixture 的作用域
Pytest 提供了几种常用 fixture 生命周期(scope):
| scope | 创建次数 | 生命周期说明 |
|---|---|---|
| function | 每个测试用例 1 次 | 用例之间完全隔离 |
| class | 每个测试类 1 次 | 同一类用例共享 |
| module | 每个模块 1 次 | 同一文件的所有用例共享 |
| session | 整个测试运行 1 次 | 测试全局共享资源 |
本质理解:
- 短生命周期适合需要隔离状态的对象(如接口客户端、登录 token)
- 长生命周期适合全局共享资源(如数据库连接、Redis 客户端)
二、真实问题复现
假设我们有两个 fixture:
python
@pytest.fixture(scope="session")
def request_util():
return RequestUtil() # 封装 HTTP 请求,带 token 状态
@pytest.fixture(scope="session")
def auth_token(request_util, test_data):
user = test_data["users"]["test_user"]
resp = request_util.post("/public/login", json={
"account": user["account"],
"password": user["password"]
})
return resp.json()["data"]["token"]
问题表现
运行测试时,批量用例报错:
ScopeMismatch: You tried to access the function scoped fixture request_util with a session scoped request object
Token 不匹配或已失效
分析:
request_util携带 token 状态,每个用例可能修改 headerauth_token是 session 级 fixture,全局依赖短生命周期 fixture → 生命周期冲突- 结果:多个用例共享同一个 request_util 与 token,状态污染 → 401
三、为什么 scope="function" 可以解决问题
1)改法示例
python
@pytest.fixture(scope="function")
def request_util():
return RequestUtil()
@pytest.fixture(scope="function")
def auth_token(request_util, test_data):
user = test_data["users"]["test_user"]
resp = request_util.post("/public/login", json={
"account": user["account"],
"password": user["password"]
})
return resp.json()["data"]["token"]
2)运行逻辑变化
原来(session):
创建 request_util + token A(只一次)
用例1 → token A
用例2 → token A(被污染)
用例3 → token A(被污染)
...
改成 function:
用例1 → 新 request_util → 登录 → token A
用例2 → 新 request_util → 登录 → token B
用例3 → 新 request_util → 登录 → token C
...
每个用例都是独立 session,token 不会相互污染 → 401 消失
四、什么时候用 session,什么时候用 function
✅ 适合 session(共享资源,不带状态)
python
@pytest.fixture(scope="session")
def db_conn():
return connect_mysql()
❌ 不适合 session(带状态对象)
python
@pytest.fixture(scope="session")
def request_util():
util = RequestUtil()
util.login() # 带 token 状态 → 多用例共享可能出问题
return util