Pytest Fixture 作用域详解:Function、Class、Module、Session 怎么选

在做接口或 UI 自动化测试时,pytest 的 fixture(夹具) 是前置/后置管理、数据准备和资源复用的利器。

很多新手最迷惑的就是 scope(作用域),比如:

  • scope="function" 是不是每个用例都用同一份?
  • scope="class" 为什么模块级函数不共享?
  • 怎么保证测试用例互不干扰?

今天我们就用 直觉 + 示例 + 面试回答 三步,把 fixture 作用域讲清楚。


一、fixture 基本语法回顾

python 复制代码
import pytest

@pytest.fixture
def data_box():
    print("\n👉 创建一份新数据")
    box = {"count": 0}
    yield box
    print("👉 清理数据")

拆解

语法部分 作用
@pytest.fixture 声明这是一个 fixture,可在测试函数中使用
def data_box(): 函数名 = 测试函数里引用 fixture 的名字
yield 前 前置操作,测试执行前运行
yield 返回值 传给测试函数,作为参数使用
yield 后 后置操作,测试执行后运行

口诀yield 前 = 前置,yield = 给用例,yield 后 = 后置


二、fixture scope 详解

pytest 提供四种作用域:

scope 意义 什么时候创建 fixture
function 默认 每个测试函数/方法都会重新创建一次
class 类级 同一个类内所有方法共用一份 fixture
module 文件级 同一个文件内所有测试函数共用一份
session 会话级 整个 pytest 运行过程中共享一份

三、scope=function:互不干扰

python 复制代码
@pytest.fixture
def data_box():
    box = {"count": 0}
    yield box
python 复制代码
def test_a(data_box):
    data_box["count"] += 1
    print("test_a:", data_box)

def test_b(data_box):
    print("test_b:", data_box)

执行结果:

复制代码
创建一份新数据
test_a: {'count': 1}
清理数据

创建一份新数据
test_b: {'count': 0}
清理数据

解释

  • 每个函数都会 重新创建 fixture
  • 所以 test_a 的修改不会影响 test_b
  • function 作用域天然隔离,用于保证用例互不干扰

直观比喻:

  • ❌ 错误:所有用例用同一桶水 → 污染
  • ✅ 正确:每个用例接新水 → 独立互不影响

四、scope=class:类内共享

python 复制代码
@pytest.fixture(scope="class")
def data_box():
    box = {"count": 0}
    yield box

注意 :class 作用域 只对类内方法生效,模块级函数不会共享。

python 复制代码
class TestDemo:
    def test_a(self, data_box):
        data_box["count"] += 1
        print("test_a:", data_box)

    def test_b(self, data_box):
        print("test_b:", data_box)

输出:

复制代码
创建一份新数据
test_a: {'count': 1}
test_b: {'count': 1}
清理数据

✅ 两个方法共享同一个 data_box,互相影响。


五、scope=session 或 module:全局共享

python 复制代码
@pytest.fixture(scope="session")
def data_box():
    box = {"count": 0}
    yield box

所有测试函数,无论是否在同一个文件或类中,都会共用同一份 fixture:

复制代码
创建全局数据
test_a: {'count': 1}
test_b: {'count': 1}   # 被污染

适合登录、数据库连接、全局客户端等场景,但要注意 清理数据


六、常见踩坑

  1. 模块级函数 + scope="class"

    • class 作用域只在类内方法生效,模块级函数还是每个用例新建。
  2. 使用全局变量

python 复制代码
GLOBAL_BOX = {"count": 0}

@pytest.fixture
def bad_fixture():
    yield GLOBAL_BOX  # 所有用例都共用 GLOBAL_BOX
  • 即使 function 作用域,也会污染用例。
  • 正确做法:在 fixture 内新建对象
  1. 操作数据库不清理
python 复制代码
@pytest.fixture
def create_order():
    order_id = insert_order_into_db()
    yield order_id
    delete_order(order_id)  # ✅ 清理数据
相关推荐
AI人工智能+电脑小能手2 小时前
【大白话说Java面试题】【Java基础篇】第15题:JDK1.7中HashMap扩容为什么会发生死循环?如何解决
java·开发语言·数据结构·后端·面试·哈希算法
Moment4 小时前
2026 年,AI 全栈时代到了,前端简历别再只写前端技术了 🫠🫠🫠
前端·后端·面试
白晨并不是很能熬夜5 小时前
【PRC】第 2 篇:Netty 通信层 — NIO 模型 + 自定义协议 + 心跳
java·开发语言·后端·面试·rpc·php·nio
M ? A7 小时前
Vue 的 scoped 样式穿透 React 不支持?用 VuReact 编译就行
前端·javascript·vue.js·react.js·面试·开源·vureact
极客沐森7 小时前
如何取消大批量的超时订单,关于超时架构的探讨
面试·架构
豹哥学前端8 小时前
10分钟彻底搞懂 window 对象、全局环境与 JS 引擎
前端·面试
QH139292318808 小时前
Rohde & Schwarz FSWX3044 FSWX3026信号与频谱分析仪
网络·功能测试·单元测试·集成测试·模块测试
一只机电自动化菜鸟10 小时前
一建机电备考笔记(27)测量技术—仪器(含考频+题型)
经验分享·笔记·学习·职场和发展·求职招聘·课程设计
白晨并不是很能熬夜10 小时前
【RPC】第 1 篇:全景篇 — 一次 RPC 调用的完整旅程
java·网络·后端·网络协议·面试·rpc·java-zookeeper
用户990450177800912 小时前
TrendRadar 热榜监控系统部署与二次开发服务
面试