7. Fixture :自动化前后置

承接前文 Pytest 用例规则、前后置 setup、断言、参数化,本篇详解Fixture 。Fixture 是 Pytest 框架最核心特色,完美解决原生setup_method/setup_class局限性,实现前后置复用、依赖注入、全局环境管理,是接口 / UI 自动化框架搭建必备。

一、Fixture 是什么?对比原生 setup 的优势

1. 概念

@pytest.fixture装饰器定义资源 / 前置后置函数,以参数注入方式被用例调用 ,自动完成环境初始化、数据准备、资源销毁,替代老旧setup/teardown

2. setup 痛点 & Fixture 优势

原生 setup/teardown 缺点 Fixture 对应优势
绑定测试类,跨类 / 跨文件无法复用 可全局定义,整个项目任意用例引用
执行粒度固定:类 / 方法两级 scope 四种作用域(function/class/module/session)灵活控制生命周期
只能顺序执行,不能互相依赖 支持 Fixture 嵌套依赖、多层调用
无法实现用例参数化前置 自带 params 参数化,实现前置数据批量驱动
前后置写死在同一个方法 yield 分割前置 / 后置,代码分离可读性强

企业选型结论:新项目全部用 Fixture 替代 setup,仅老旧 unittest 项目兼容保留 setup 写法。

二、Fixture 基础入门:参数注入调用

1. 基础语法:定义 & 调用规则

@pytest.fixture修饰的函数,函数名直接作为测试用例形参,pytest 自动优先执行 fixture,再跑用例

python 复制代码
import pytest
# 定义fixture
@pytest.fixture
def login():
    print("【fixture】执行登录,获取token")
    return "token_123456"

# 用例通过形参传入login,自动触发执行
def test_list_page(login):
    print("访问列表页,携带{}请求".format(login))

def test_detail_page(login):
    print("访问详情页,携带{}请求".format(login))

执行结果:每条用例运行前自动执行 login 登录,实现登录逻辑复用,不用每个用例重复写登录代码。

复制代码
【fixture】执行登录,获取token
访问列表页,携带token_123456请求
【fixture】执行登录,获取token
访问详情页,携带token_123456请求

2. fixture 嵌套依赖(链式调用)

fixture 可依赖其他 fixture,pytest 自动按依赖顺序逐层执行,适合分层初始化:比如先创建订单→再创建订单商品。

python 复制代码
@pytest.fixture
def entry():
    return ["a"]

# 依赖entry fixture
@pytest.fixture
def order(entry):
    entry.append("b")
    return entry

# 用例只需要传入最外层order,自动先执行entry再执行order
def test_order_operate(order):
    assert order == ["a","b"]

3. 一个用例传入多个 fixture

用例形参可一次性接收多个 fixture,多个前置资源并行加载:

python 复制代码
@pytest.fixture
def fruit_apple():
    return "apple"
@pytest.fixture
def fruit_banana():
    return "banana"
# 同时接收两个fixture
def test_fruit_basket(fruit_apple,fruit_banana):
    basket = [fruit_apple,fruit_banana]
    assert len(basket) ==2

三、yield 实现前后置分离(Fixture 精髓)

return只能返回数据无法做后置,yield 关键字拆分前后置:yield 之前 = 用例执行前 (前置),yield 之后 = 用例跑完后 (后置),完美实现资源创建 + 销毁闭环(打开 / 关闭文件、连接 / 断开数据库)。

示例 1:通用初始化 & 清理模板

python 复制代码
@pytest.fixture
def open_close():
    # ==========前置:用例执行前
    print("前置:初始化连接资源")
    yield "资源对象" # 返回值传给用例
    # ==========后置:用例执行完毕
    print("后置:销毁、关闭资源")

def test_demo(open_close):
    print("执行测试用例,使用{}".format(open_close))

运行输出:

python 复制代码
前置:初始化连接资源
执行测试用例,使用资源对象
后置:销毁、关闭资源

示例 2:文件读写实战(创建文件→读写→自动关闭)

python 复制代码
@pytest.fixture
def file_handle():
    # 前置:打开文件
    f = open("test.txt","w+",encoding="utf-8")
    yield f
    # 后置:自动关闭文件,避免资源泄漏
    f.close()
    print("文件已关闭")

def test_file_opt(file_handle):
    file_handle.write("测试数据")
    file_handle.seek(0)
    content = file_handle.read()
    assert content == "测试数据"

四、scope 作用域:控制 Fixture 生命周期(4 种粒度)

@pytest.fixture(scope="粒度"),控制 fixture 多久创建销毁,从细到粗 4 个取值:

scope 取值 生效范围 执行规则 适用场景
function (默认) 单个测试用例 每条用例执行前后各运行 1 次 单用例独立临时数据、单次接口临时账号
class 测试类 一个测试类所有用例共用 1 次,类开头创建,类全部跑完销毁 一个模块下多个接口共用登录 token
module 单个 py 文件 当前整个.py 脚本所有用例只初始化 1 次 单个模块全局数据库连接
session 整个测试会话 项目全部用例只执行 1 次(全局) 整个自动化项目全局登录、环境初始化

示例:scope=class 类级别复用

python 复制代码
@pytest.fixture(scope="class")
def class_login():
    print("【类前置:仅执行1次】登录")
    yield
    print("【类后置:类结束销毁】退出登录")

class TestApi:
    def test_case1(self,class_login):
        print("用例1执行")
    def test_case2(self,class_login):
        print("用例2执行")

运行:整个类只登录 1 次,两个用例共用登录态,类跑完才退出登录。

session/module 一般配合conftest.py全局文件使用,实现跨文件全局前置。

五、autouse 自动执行:无需传参,全局自动生效

autouse=True:不用在用例形参填写 fixture 名称,满足 scope 范围的所有用例自动执行该 fixture,适合全局统一配置(全项目统一初始化日志、全局环境变量)。

python 复制代码
# 当前类下所有用例自动执行,不用手动传参
@pytest.fixture(scope="class",autouse=True)
def auto_setup():
    print("自动执行类前置")
    yield
    print("自动执行类后置")

class TestDemo:
    def test_a(self):
        pass
    def test_b(self):
        pass

六、params 参数化 Fixture:前置数据源批量驱动

fixture 内置params=数据集,实现 fixture 自身参数化,每组数据生成一条用例

侧重前置环境多组数据初始化,区别于@pytest.mark.parametrize用例参数化(侧重接口入参)。

python 复制代码
# params提供多组数据,自动循环生成多条用例
@pytest.fixture(params=["admin","user1","user2"])
def init_user(request):
    # request.param获取当前遍历参数
    print(f"创建用户:{request.param}")
    return request.param

# 不用额外参数化,自动3条用例
def test_user_login(init_user):
    print(f"用户{init_user}登录测试")

区别对比:

七、conftest.py 全局配置文件(项目级 fixture)

1. 规则

  1. 文件名固定 conftest.py 不可修改,放在项目目录;
  2. 同目录 + 子目录所有 py 脚本不用 import 导入,直接调用文件内 fixture
  3. 一般存放scope=module/session全局 fixture(全局登录、全局数据库连接),实现跨文件前后置复用。

项目目录结构

复制代码
项目根目录
├─ conftest.py    # 全局fixture
├─ test_case1/
│   └─ test_api1.py
└─ test_case2/
    └─ test_api2.py

conftest.py 代码:

python 复制代码
@pytest.fixture(scope="session")
def global_env():
    print("【全局session】整个项目只初始化一次环境")
    yield
    print("【全局销毁】项目所有用例跑完清理环境")

test_api1.py 直接使用:

python 复制代码
def test_demo(global_env):
    pass

八、Fixture 和 parametrize 参数化选型区别

  1. @pytest.mark.parametrize用例入参参数化,侧重接口请求参数、业务入参变化;
  2. fixture(params)前置资源参数化,侧重测试环境、前置准备数据变化(不同测试账号、不同测试环境)。

九、接口自动化综合实战(整合前文:前后置 + fixture + 断言)

python 复制代码
import pytest,requests
# 全局登录fixture
@pytest.fixture(scope="module")
def get_token():
    # 前置:登录接口拿token
    login_url = "https://jsonplaceholder.typicode.com/users/1"
    res = requests.get(login_url)
    token = f"token_{res.json()['id']}"
    yield token
    # 后置:登出
    print("登出账号,销毁token")

# 业务接口用例
def test_query_info(get_token):
    headers = {"token":get_token}
    res = requests.get("https://jsonplaceholder.typicode.com/posts/1",headers=headers)
    # 断言
    assert res.status_code ==200,"接口请求失败"
    assert res.json()["userId"] ==1

十、高频踩坑总结

  1. yield 前后代码严格分开:yield 前前置、yield 后后置,异常时 yield 之后代码依然会执行;
  2. conftest 就近原则:子目录 conftest 优先级高于根目录,就近调用;
  3. autouse 慎用:全局 autouse 容易出现多余前置,仅公共环境配置使用;
  4. scope=session 仅整个 pytest 命令执行一次,分开多次 pytest 执行会重复初始化。
相关推荐
遇见火星1 小时前
从0到1掌握Ansible:让自动化运维不再是梦想
运维·自动化·ansible
文青小兵1 小时前
Linux云计算——docker 告警(六)
linux·运维·docker·云计算·prometheus
xiep14383335101 小时前
CentOS 7.9 安装 TigerVNC
linux·运维·centos
2601_957190901 小时前
实战落地为王,全尺寸定制飞行影院适配全场景文旅升级
大数据·运维·人工智能
光电笑映1 小时前
进程间通信(上):深入理解管道与进程池
linux·运维·服务器
Maydaycxc1 小时前
Excel/WPS 自动化实战:科学计数法、千张表格循环处理、打包交付的多工具对比
python·自动化·excel·wps·rpa
提伯斯6461 小时前
Linux minicom 串口工具超详细使用教程
linux·运维·服务器
艾莉丝努力练剑1 小时前
【Linux网络】网络层IP协议(一)
linux·运维·服务器·网络·tcp/ip·计算机网络·udp
古月开发1 小时前
智能客服系统设计避坑指南:从需求分析到持续优化
人工智能·自动化·个人开发