Python的pytest框架(3)--fixtrue固件

fixture是pytest的一项核心特性,它提供了一种组织和管理测试依赖项(如初始化环境、创建资源、清理操作等)的有效机制。下面将对fixture进行深入讲解,包括其基本概念、作用、使用方式、特性以及高级应用:

目录

一、基本概念

二、fixture的定义与使用

三、fixture特性

[fixture 生命周期](#fixture 生命周期)

fixture参数:

scope(作用域)

autouse(是否自动执行)

params(参数化)

ids(参数别名)

name(固件别名)

fixture依赖:

四、conftest.py--集中管理fixture固件

创建conftest.py文件

使用conftest.py中的内容

五、什么情况下使用fixture?


一、基本概念

fixture 是指在执行特定测试之前设置特定环境或状态 ,以及在测试完成后清理或还原这些状态的一种机制。它可以用来准备任何测试所需的共享资源,如数据库连接、临时文件、网络服务、模拟数据等。fixture的核心价值在于:

  1. 标准化测试环境:确保每次运行测试时,都基于一致的初始条件,提高测试的可重复性和可靠性。
  2. 资源管理:自动处理资源的创建、使用和销毁,避免测试间资源泄漏或污染。
  3. 代码复用:通过模块化的设计,让多个测试能够共享相同的fixture,减少冗余代码。

二、fixture的定义与使用

fixture在pytest中通过装饰器 @pytest.fixture 标记。一个基本的fixture定义如下:

python 复制代码
import pytest

@pytest.fixture
def example_fixture():
    # 准备阶段:执行创建或初始化资源的逻辑
    resource = create_some_resource()

    yield resource  # 这里yield语句使得测试函数可以在运行时访问到fixture返回的对象

    # 清理阶段:在测试结束后执行清理逻辑
    cleanup_resource(resource)

要使用fixture,只需将其作为参数传递给测试函数:

python 复制代码
def test_example_usage(example_fixture):
    # 测试函数在执行时,example_fixture对应的fixture会先被调用,
    # 然后将返回值传递给测试函数作为参数
    assert do_something_with(example_fixture) == expected_result

三、fixture特性

fixture 生命周期

fixture 的生命周期主要包括三个阶段:

setup: 当测试函数需要某个 fixture 时,pytest 会先调用对应的 fixture 函数。fixture 函数负责初始化所需资源、创建数据或设置特定环境状态。如果 fixture 依赖其他 fixture,那么这些依赖的 fixture 会按照依赖顺序先被 setup。

use: fixture 函数通过 yield 语句返回的值或对象,会在测试函数执行期间作为参数传入并使用。测试函数可以自由操作这些资源,执行测试逻辑。

teardown: 测试函数执行完毕后,pytest 会继续执行 yield 语句之后的清理代码,这里负责释放资源、删除临时文件、关闭数据库连接、恢复环境状态等操作,确保测试的副作用得到清除。

fixture参数:

@pytest.fixture(scope="作用域",autouse="是否自动执行",params="参数化",ids="参数别

名",name="固件别名")

我们分开来讲述这些参数的具体作用

scope(作用域)

控制fixture的作用域,可选值包括 "function"(默认为function)、"class"、"module"、"package" 或 "session"。作用域决定了fixture的生命周期和复用范围:

function: 每当有测试函数请求此fixture时,pytest会为其创建一个新的fixture实例。这意味着每个测试函数都会得到一个独立的fixture副本。

class : 在类中首个依赖此fixture的测试函数执行前,pytest会创建一个fixture实例。该实例会被类中所有依赖此fixture的测试函数共享。
module : 在模块中首个依赖此fixture的测试函数执行前,pytest会创建一个fixture实例。该实例会被模块内所有依赖此fixture的测试函数共享。
package : 在包中首个依赖此fixture的测试函数执行前,pytest会创建一个fixture实例。该实例会被包内所有依赖此fixture的测试函数共享。
session: 在测试会话开始时,pytest会创建一个fixture实例。该实例会被会话中所有依赖此fixture的测试函数共享。

python 复制代码
@pytest.fixture(scope="module")
def module_level_fixture():
    ...

#scope='module' 只创建一次,会作用到整个模块

autouse(是否自动执行)

如果设为 True,则无需显式在测试函数签名中指定该fixture,它会自动应用于所有匹配其作用域的测试,默认为False。

python 复制代码
@pytest.fixture(autouse=True)
def always_used_fixture():
    print("测试前准备前置操作")
    yield
    print("测试完毕释放资源操作")

def test_example_usage():
    # 测试函数在执行时,无需传入always_used_fixture对应的fixture也会被调用,
    pass


@pytest.fixture(autouse=False)
def always_used_fixture():
    print("测试前准备前置操作")
    yield
    print("测试完毕释放资源操作")

def test_example_usage(always_used_fixture):
    # 测试函数在执行时,需传入always_used_fixture对应的fixture才被调用,
    pass

params(参数化)

pytest 支持对 fixture 进行参数化,这意味着一个 fixture 可以根据不同的输入参数产生多种不同的预备状态。参数化 fixture 可以极大地提高测试的覆盖范围和灵活性。要实现参数化 fixture,可以使用 pytest.mark.parametrize 装饰器同时装饰 fixture 函数和依赖它的测试函数,或者直接在 fixture 函数上使用 params 关键字参数。以下是一个参数化 fixture 的示例:

python 复制代码
import pytest

@pytest.fixture(params=[1, 2, 3])
def input_fixture(request):
    value = request.param
    return value

def test_multiply_by_two(input_fixture):
    assert input_fixture * 2 == input_fixture + input_fixture

在这个例子中,input_fixture是一个参数化的fixture,其params关键字参数设置为列表[1, 2, 3]。这意味着每次test_multiply_by_two函数运行时,input_fixture将会接收到列表中的一个不同值。因此,test_multiply_by_two函数会被执行三次,分别使用参数值1, 2 和 3。

ids(参数别名)

为参数化fixture的每个实例提供易于识别的标识,便于在测试报告中区分。

python 复制代码
@pytest.fixture(params=[1, 2, 3], ids=["one", "two", "three"])
def named_parametrized_fixture(request):
    value = request.param
    ...

name( 固件别名**)**

自定义fixture的名称,仅在需要覆盖默认生成的fixture名称时使用。

python 复制代码
@pytest.fixture(name="custom_name")
def my_fixture():
    ...

fixture依赖:

fixture之间可以相互依赖。一个fixture在其定义中可以通过接受其他fixture作为参数来声明依赖关系。当依赖的fixture被请求时,pytest会确保先执行依赖fixture的setup部分,再执行当前fixture,最后在测试结束时按照相反顺序执行清理操作。

python 复制代码
@pytest.fixture
def database_connection():
    conn = establish_db_conn()
    yield conn
    close_db_conn(conn)


@pytest.fixture
def initialized_table(database_connection):
    create_table(database_connection)
    populate_table(database_connection)
    yield
    truncate_table(database_connection)


def test_query(initialized_table):
    rows = execute_query(initialized_table)
    assert len(rows) > 0

在这里,initialized_table fixture依赖于database_connection fixture。当test_query 函数请求initialized_table 时,pytest会确保先执行database_connection 的setup部分(建立数据库连接),然后执行initialized_table 的setup(创建表并填充数据)。测试结束后,先清理initialized_table (清空表),再清理database_connection(关闭连接)。

四、conftest.py--集中管理fixture固件

conftest.py 是 pytest 测试框架中一个特殊且非常重要的文件,主要用于存放与测试相关的配置、全局设置以及可复用的fixture(固件)

创建conftest.py文件

在需要使用fixture或进行特定配置的目录下创建名为 conftest.py 的文件。可以创建在项目根目录下(影响整个项目),也可以创建在特定的测试子目录下(仅影响该目录及其子目录)

在conftest.py文件中可以定义fixture固件,也可以通过 pytest.mark 装饰器为所有测试添加标记(markers)

使用conftest.py中的内容

无需在测试代码中显式导入或引用 conftest.py 。pytest会自动发现并加载所有有效的 conftest.py 文件根据其位置确定其作用域,并在相应范围内应用其中定义的fixture和配置。

总结而言,conftest.py 文件是pytest框架中用于集中管理测试配置、定义可复用fixture以及定制测试执行流程的关键组件。通过在适当位置创建 conftest.py 并编写相应的代码,可以极大地提升测试代码的组织性、可维护性和执行效率。

五、什么情况下使用fixture?

需要共享资源或数据:当你有一组测试都需要访问同一个数据库、文件、网络连接或其他资源时,用fixture来统一管理和初始化这些资源,确保每个测试获得的是正确且独立的状态。

需要复杂的环境设置:如果你的测试需要复杂的环境配置,如启动服务、设置系统权限、模拟外部接口响应等,使用fixture来封装这些复杂的设置和清理逻辑,使测试代码聚焦于核心测试行为。

需要重复的初始化或清理:如果有多个测试需要进行相似的初始化(如填充固定测试数据)或清理(如删除临时文件、重置系统状态)操作,使用fixture可以避免在每个测试中重复编写这些代码。

需要参数化测试:当你希望一个测试用例针对不同输入参数运行多次时,可以使用参数化的fixture为测试函数提供一组或多组不同的预备环境或数据,从而增加测试覆盖率。

希望以上内容能帮助大家高效理解pytest框架的fixture固件,让fixture帮助测试变得更高效可靠

相关推荐
数据智能老司机1 小时前
精通 Python 设计模式——并发与异步模式
python·设计模式·编程语言
数据智能老司机1 小时前
精通 Python 设计模式——测试模式
python·设计模式·架构
数据智能老司机1 小时前
精通 Python 设计模式——性能模式
python·设计模式·架构
c8i1 小时前
drf初步梳理
python·django
每日AI新事件1 小时前
python的异步函数
python
这里有鱼汤2 小时前
miniQMT下载历史行情数据太慢怎么办?一招提速10倍!
前端·python
databook11 小时前
Manim实现脉冲闪烁特效
后端·python·动效
程序设计实验室12 小时前
2025年了,在 Django 之外,Python Web 框架还能怎么选?
python
倔强青铜三13 小时前
苦练Python第46天:文件写入与上下文管理器
人工智能·python·面试
用户25191624271117 小时前
Python之语言特点
python