Skip to content

Fixture

自测题

完成以下 3 道题目,检验你的学习成果

问题 1

Pytest 中 session 级和 function 级 Fixture 的主要区别是什么?

问题 2

Fixture 嵌套过深会导致什么问题?

问题 3

Fixture 应该专注于什么?

基础入门

Fixture 是 pytest 测试框架中的核心机制,用于统一管理测试依赖。

它的核心作用是:为测试准备前置条件(如登录态、数据库连接、测试数据),并在测试结束后清理资源(如删除测试数据、断开连接)。Fixture 让测试代码更简洁、更复用、更易维护。

举个例子:测试下单功能需要先登录获取 token、准备测试商品、创建测试用户。\n\n如果没有 Fixture,每个测试都要重复写这些准备代码。有了 Fixture,可以把登录、准备商品、创建用户封装成三个 Fixture,测试代码只需声明依赖,pytest 会自动注入。

Fixture 的核心优势有四:

一是作用域灵活(function、module、session)。

二是依赖注入(测试函数通过参数名自动获取 Fixture)。

三是可组合(Fixture 可以依赖其他 Fixture)。

四是资源清理(用 yield 语法在测试后自动清理)。

面试时能讲清作用域选择和依赖注入机制,能体现对 pytest 的深入理解。

为什么重要

  • 提升代码复用:Fixture 把公共准备逻辑封装一次,多处复用,避免重复代码。
  • 提高执行效率:session 级 Fixture 全局复用(如登录态),避免每个测试都重新初始化,大幅减少执行时间。
  • 面试高频考点:「Pytest 里你怎么设计通用 Fixture」「session 级和 function 级怎么取舍」是测试开发面试的经典问题。
  • 测试隔离保障:function 级 Fixture 保证每个测试独立准备数据,测试间互不影响,失败定位更准确。
  • 框架建设能力:面试官常用 Fixture 设计判断候选人是否真正做过框架建设,而不只是会写脚本。

前置知识

  • Python 基础:理解函数定义、参数传递、装饰器语法(@pytest.fixture)。
  • pytest 基础:了解 pytest 测试用例的写法(test_开头的函数)、assert 断言语法。
  • 作用域概念:理解 function、module、session 等作用域的含义,知道不同作用域的生命周期。
  • 测试隔离概念:理解为什么测试需要独立数据,知道测试间相互干扰会导致什么问题。
  • 资源管理概念:理解「准备 - 使用 - 清理」的资源管理模式,知道测试后清理数据的重要性。

学习路径

  • 第一阶段:理解概念。学习 Fixture 的定义、作用、基本语法,理解为什么需要 Fixture。
  • 第二阶段:基础用法。练习编写简单的 Fixture(如准备测试数据)、使用 yield 清理资源、理解 function 作用域。
  • 第三阶段:作用域选择。学习 function、module、session 级 Fixture 的区别,掌握作用域选择原则(成本 vs 隔离)。
  • 第四阶段:依赖注入。理解 Fixture 如何通过参数注入被测试使用,学习 Fixture 依赖其他 Fixture 的写法。
  • 第五阶段:工程化实践。学习 conftest.py 组织全局 Fixture、Fixture 分层设计、Fixture 与参数化配合。
  • 第六阶段:进阶实践。学习 Fixture 动态参数化(request 参数)、Fixture 与插件配合(如 pytest-django、pytest-asyncio)。

实操案例:三层 Fixture 设计

场景:某电商测试项目需要设计通用 Fixture 体系,支撑上百个测试用例。

解决方案:三层 Fixture 设计

第一层:基础层 Fixture(session 作用域)

@pytest.fixture(scope="session")
def db_connection():
"""数据库连接,整个测试会话共用"""
conn = create_connection()
yield conn
conn.close()
@pytest.fixture(scope="session")
def auth_token():
"""登录态,整个测试会话只登录一次"""
token = login("test_user", "password")
yield token
logout(token)

基础层 Fixture 负责最底层的资源初始化,成本高、隔离需求低,适合 session 作用域。

第二层:业务层 Fixture(module/function 作用域)

@pytest.fixture(scope="module")
def test_user(db_connection):
"""测试用户,每个测试模块共用一个"""
user = create_user(db_connection)
yield user
delete_user(db_connection, user.id)
@pytest.fixture(scope="function")
def test_order(db_connection, test_user):
"""测试订单,每个测试独立一个"""
order = create_order(db_connection, test_user.id)
yield order
delete_order(db_connection, order.id)

业务层 Fixture 依赖基础层 Fixture,通过参数注入组合。test_user 用 module 作用域(同一模块复用),test_order 用 function 作用域(每个测试独立)。

第三层:场景层 Fixture(按需组合)

@pytest.fixture
def paid_order(test_order):
"""已支付的订单场景"""
pay_order(test_order.id)
yield test_order
@pytest.fixture
def shipped_order(paid_order):
"""已发货的订单场景"""
ship_order(paid_order.id)
yield paid_order

场景层 Fixture 通过组合多层 Fixture 构建特定业务场景,测试时直接注入使用。

面试表达要点:强调 Fixture 分层原则(基础层 session、业务层 module/function、场景层按需),依赖注入实现组合,作用域选择权衡成本和隔离。

实操案例:Fixture 作用域选择

场景:项目中 Fixture 作用域混乱,导致执行时间长、测试不稳定。

解决方案:按资源特性选择作用域

session 作用域(全局复用) 适用场景:

  • 登录态获取(调用接口、等待响应,成本高)
  • 配置加载(读取配置文件、解析,成本低但全局共用)
  • 全局资源(如 Redis 连接池、日志初始化) 判断标准:初始化成本高、隔离需求低、全局共用安全

module 作用域(模块内复用) 适用场景:

  • 数据库连接(建立连接有网络开销,同一模块内可复用)
  • API 客户端(初始化耗时,模块内复用)
  • 测试数据模板(如商品模板、用户模板,模块内复用) 判断标准:初始化成本中等、隔离需求中等、模块内复用安全

function 作用域(每个测试独立) 适用场景:

  • 测试数据(每个测试需要独立数据,避免相互影响)
  • 会修改状态的操作(如下单、支付,测试后需要清理)
  • 隔离需求高的资源(如浏览器实例,测试间不能共用) 判断标准:隔离需求高、成本低或必须独立

面试表达要点:强调作用域选择原则是「资源成本 vs 隔离需求」。session 级节省时间但隔离性差,function 级隔离性好但开销大。要根据资源特性选择合适作用域,同时控制 Fixture 嵌套深度在 2-3 层。

常见误区

误区一:所有 Fixture 都做成 function 级别

所有 Fixture 都设为 function 作用域会导致每个测试都重新初始化,执行时间大幅增加。

正确做法是:根据资源成本和隔离需求选择作用域,登录态用 session(成本高、无需隔离)、数据库连接用 module(成本中等、模块内复用)、测试数据用 function(隔离需求高)。面试时要讲清作用域选择原则和性能权衡。

误区二:Fixture 嵌套太深

Fixture 嵌套层级过多会让依赖关系难以追踪,阅读成本高。

正确做法是:控制嵌套深度在 2-3 层,复杂依赖拆成多个独立 Fixture 并通过参数注入组合。\n\n例如登录态 Fixture 和订单数据 Fixture 独立定义,场景 Fixture 通过参数注入组合两者,而不是在一个 Fixture 里做所有准备。面试时要举一个 Fixture 依赖设计的具体案例。

误区三:混入大量业务逻辑

Fixture 应专注于环境准备和资源管理,如果混入业务逻辑会导致难以复用和维护。

正确做法是:Fixture 只做环境层(登录态、数据库、浏览器),业务数据准备放在测试代码或 helper 函数。\n\n例如 Fixture 负责创建订单记录,但订单金额计算逻辑应该放在 helper 函数中。面试时要讲清 Fixture 与业务逻辑的边界划分。

误区四:忽略资源清理

测试后不清理数据会导致数据污染、测试相互干扰。

正确做法是:使用 yield 语法在 Fixture 中清理资源,如删除测试数据、断开连接。对于 function 作用域的 Fixture,pytest 会在测试结束后自动执行 yield 后的清理代码。

面试时要强调:Fixture 的清理逻辑和准备逻辑同等重要。

误区五:Fixture 命名不清晰

Fixture 名称晦涩难懂会让测试代码可读性变差。

正确做法是:用描述性的名称(如 auth_token、test_user、paid_order),让测试代码一目了然。避免使用 a、b、data 等无意义名称。

面试时要说明:Fixture 命名是测试可维护性的重要体现。

面试问答

Pytest 里你怎么设计通用 Fixture?

通用 Fixture 的设计围绕三个原则:复用性、可组合性、隔离性。

第一,按资源类型分层设计。我通常分成三层:基础层(数据库连接、配置加载、登录态)用 session 作用域全局复用。业务层(测试用户、测试商品)用 module 或 function 作用域按需复用。场景层(已支付订单、已发货订单)通过参数注入组合多层 Fixture。

第二,Fixture 之间可组合不耦合。每个 Fixture 只做一件事,复杂场景通过 Fixture 参数注入组合,如登录态 Fixture + 订单数据 Fixture 组成下单场景 Fixture。

第三,Fixture 有明确的职责边界。Fixture 只负责环境准备和资源管理,不混入业务逻辑。

面试时可以举例:我们的登录态 Fixture 用 session 作用域,整个测试会话只登录一次。测试数据 Fixture 用 function 作用域,每个测试独立准备和清理数据。

session 级和 function 级 Fixture 怎么取舍?

取舍原则是「资源成本 vs 隔离需求」。session 级 Fixture 适合高成本、低隔离的资源,如登录态(获取需要调用接口、等待响应)。function 级 Fixture 适合低成本、高隔离的资源,如测试数据(每个测试需要独立数据)。

具体判断方法:一看资源初始化成本,成本高优先考虑 session 级。二看隔离需求,需要独立数据用 function 级。三看执行时间权衡,session 级节省时间但隔离性差。

面试时要强调:不是所有 Fixture 都设成 session 或 function,要根据资源特性选择合适作用域,同时控制 Fixture 嵌套深度在 2-3 层。

Fixture 如何实现依赖注入?

pytest 通过参数名匹配实现依赖注入。测试函数或 Fixture 的参数名如果与某个 Fixture 同名,pytest 会自动注入该 Fixture 的返回值。\n\n例如定义一个 auth_token 的 Fixture 后,任何测试函数只要参数名为 auth_token,就能自动获取登录态。

依赖注入的好处是:测试代码无需显式调用 Fixture,依赖关系清晰。Fixture 可以链式依赖,形成依赖树。

面试时可以举例:test_order Fixture 依赖 test_user,只需把 test_user 作为参数传入,pytest 会先执行 test_user Fixture 再执行 test_order。

conftest.py 的作用是什么?

conftest.py 是 pytest 的局部配置目录,用于存放可复用的 Fixture 和配置。放在 conftest.py 中的 Fixture 可以被同目录及子目录下的所有测试文件使用,无需显式导入。

好处是:Fixture 集中管理、测试文件无需 import、目录结构清晰。通常做法是:项目根目录的 conftest.py 放全局 Fixture(如数据库连接),模块目录的 conftest.py 放模块级 Fixture(如特定业务的测试数据)。面试时要说明:conftest.py 是 pytest 工程化的重要组成部分。

自测题

完成以下 3 道题目,检验你的学习成果

问题 1

Pytest 中 session 级和 function 级 Fixture 的主要区别是什么?

问题 2

Fixture 嵌套过深会导致什么问题?

问题 3

Fixture 应该专注于什么?