【Pytest】Pytest框架快速入门

目录

  • [1 何为测试框架?](#1 何为测试框架?)
  • [2 Pytest框架简介](#2 Pytest框架简介)
  • [3 快速上手](#3 快速上手)
    • [3.1 Pytest安装与启动](#3.1 Pytest安装与启动)
    • [3.2 读懂Pytest执行结果](#3.2 读懂Pytest执行结果)
      • [3.2.1 代码示例及结果解读](#3.2.1 代码示例及结果解读)
      • [3.2.2 Pytest用例结果](#3.2.2 Pytest用例结果)
  • [4 用例规则](#4 用例规则)
    • [4.1 用例发现规则](#4.1 用例发现规则)
    • [4.2 用例内容规则](#4.2 用例内容规则)
  • [5 框架配置方法](#5 框架配置方法)
  • [6 标记mark](#6 标记mark)
    • [6.1 用户自定义标记:测试用例分类与分组](#6.1 用户自定义标记:测试用例分类与分组)
    • [6.2 框架内置标记](#6.2 框架内置标记)
      • [6.2.1 parametrize 参数化](#6.2.1 parametrize 参数化)
      • [6.2.2 skip 无条件跳过](#6.2.2 skip 无条件跳过)
      • [6.2.3 skipif 有条件跳过](#6.2.3 skipif 有条件跳过)
      • [6.2.4 xfail 预期失败](#6.2.4 xfail 预期失败)
      • [6.2.5 usefixtures:使用fixtures](#6.2.5 usefixtures:使用fixtures)
  • [7 数据驱动测试](#7 数据驱动测试)
  • [8 夹具fixture](#8 夹具fixture)
    • [8.1 如何创建fixture](#8.1 如何创建fixture)
    • [8.2 如何使用fixture](#8.2 如何使用fixture)
    • [8.3 fixture高级用法](#8.3 fixture高级用法)
  • 写在最后

1 何为测试框架?

框架指的是抽象出来的工具集合,提供大量的组件、工具、功能,测试框架通常包括如下几种功能:

  • 用例发现
  • 用例管理
  • 环境管理
  • 用例执行
  • 测试报告

常见的测试框架如下:

  • java:junit,testng
  • python:unittest,pytest

2 Pytest框架简介

Pytest 是一个成熟的 Python 测试框架,广泛用于单元测试、集成测试和功能测试。它以简单易用、灵活强大著称,能够显著提升测试效率。‌

主要特点如下:

  • 简单易上手‌: 语法简洁,支持基本断言(assert),无需复杂配置即可快速编写测试用例。‌
  • 强大的插件生态‌: 可通过插件扩展功能,如生成 HTML 报告(pytest-html)、集成持续工具(如 Jenkins)或支持异步测试。‌
  • 灵活的执行控制‌: 支持参数化测试、测试跳过、失败重跑(--reruns)以及分组执行(通过 @pytest.mark 标记)。‌
  • 详细报告与集成‌: 能生成自定义报告(如 Allure 或 XML 格式),便于分析测试结果并与 CI/CD 流程结合。‌

‌基本使用规则‌

  • ‌命名规范‌:测试文件需以 test_ 开头或 _test 结尾;测试类名以 Test 开头且无 init 方法;测试方法名以 test_ 开头。
  • ‌执行方式‌:可通过命令行直接运行(如 pytest -vs),或通过配置文件(如 pytest.ini)定义默认参数(如测试路径、标记等)

3 快速上手

3.1 Pytest安装与启动

bash 复制代码
pip install pytest  # 安装pytest
pip install pytest -U  # 已经安装过pytest,升级到最新版

启动方式有如下三种:

  1. 命令行方式
bash 复制代码
pytest  # 在文件所在目录命令行执行
  1. 代码
python 复制代码
import pytest

pytest.main()
  1. 鼠标点击Pycharm启动按钮(不推荐)

3.2 读懂Pytest执行结果

3.2.1 代码示例及结果解读

首先我们先编写如下两个用例示例:

python 复制代码
def test_list():
    a = list('aaaaaa')
    b = list('aaaabc')
    assert a == b


def test_dict():
    a = {"a": 1, "b": 2, "c": 3}
    b = {"a": 2, "b": 2, "c": 3}
    assert a == b

执行后结果如下:

复制代码
D:\Anaconda3\envs\pytest\python.exe D:/git-code/python/python/my_pytest/main.py
============================= test session starts =============================
platform win32 -- Python 3.8.20, pytest-8.3.5, pluggy-1.5.0
rootdir: D:\git-code\python\python\my_pytest
collected 2 items

test_data.py FF                                                          [100%]

================================== FAILURES ===================================
__________________________________ test_list __________________________________

    def test_list():
        a = list('aaaaaa')
        b = list('aaaabc')
>       assert a == b
E       AssertionError: assert ['a', 'a', 'a', 'a', 'a', 'a'] == ['a', 'a', 'a', 'a', 'b', 'c']
E         
E         At index 4 diff: 'a' != 'b'
E         Use -v to get more diff

test_data.py:4: AssertionError
__________________________________ test_dict __________________________________

    def test_dict():
        a = {"a": 1, "b": 2, "c": 3}
        b = {"a": 2, "b": 2, "c": 3}
>       assert a == b
E       AssertionError: assert {'a': 1, 'b': 2, 'c': 3} == {'a': 2, 'b': 2, 'c': 3}
E         
E         Omitting 2 identical items, use -vv to show
E         Differing items:
E         {'a': 1} != {'a': 2}
E         Use -v to get more diff

test_data.py:10: AssertionError
=========================== short test summary info ===========================
FAILED test_data.py::test_list - AssertionError: assert ['a', 'a', 'a', 'a', ...
FAILED test_data.py::test_dict - AssertionError: assert {'a': 1, 'b': 2, 'c':...
============================== 2 failed in 0.08s ==============================

Process finished with exit code 0
  1. 执行环境:版本、根目录、用例数量
  2. 执行过程:文件名称、用例执行结果、执行进度
  3. 失败详情:用例内容、断言提示,描述用例错误原因
  4. 整体摘要:执行结果、花费时间等

3.2.2 Pytest用例结果

缩写 单词 含义
. passed 通过
F failed 失败(执行用例时报错)
E error 出错(fixture执行报错)
s skipped 跳过
X xpassed 预期外的通过(不符合预期)
x xfailed 预期内的失败(符合预期)

4 用例规则

4.1 用例发现规则

测试框架在识别、加载用例的过程,即为:用例发现

Pytest发现用例的步骤如下:

  1. 遍历所有目录,除了.开头以及虚拟环境venv的目录
  2. 打开python文件,识别的python文件需要以 test_ 开头或者以 _test.py 结尾
  3. 遍历所有以Test开头的类
  4. 收集所有 test_ 开头的方法

4.2 用例内容规则

文件名规则

文件名需以 test_*.py*_test.py 的格式命名,即要么以 test_ 开头,要么以 _test.py 结尾,例如 test_example.py 或者 example_test.py 这类文件名可以被 Pytest 当作测试用例文件发现

函数名规则

若文件中存在以 test_ 开头的函数,也会被识别为测试用例。比如 test_function() 这样的函数就符合要求

类名规则

类名要以 Test 开头,并且类中不能包含 __init__ 方法。此类下以 test_ 开头的方法也会被当作测试用例。例如 TestClass 类中的 test_method() 方法就会被 Pytest 发现

其他规则

  • 所有的包(package)必须要有 __init__.py 文件。
  • 断言使用 assert 语句

5 框架配置方法

通过配置框架来改变Pytest的默认规则

  1. 命令参数
  2. pytest.ini 文件

可以通过命令行的方式,查看如何配置

bash 复制代码
pytest -h

下面对一些常见的配置简要介绍

常用参数

  • -v :增加详细chegndu
  • -s :在用例中正常的使用输入和输出
  • -x :快速退出,当遇到失败的用例停止执行
  • -m :用例筛选

6 标记mark

pytest mark 是 Pytest 框架中一个强大的功能,可用于对测试用例进行分类、分组、参数化、跳过执行等操作,进而实现对测试用例的精细控制与管理。

6.1 用户自定义标记:测试用例分类与分组

使用 @pytest.mark.<your_marker> 可对测试用例进行分类与分组,在运行测试时依据这些分类来选择或排除测试用例。例如,使用 @pytest.mark.smoke 标记的测试用例属于冒烟测试,运行 pytest -m "smoke" 可只运行冒烟测试;运行 pytest -m "not slow" 可排除耗时用例;运行 pytest -m "smoke or slow" 可执行冒烟测试或耗时测试用例

用户自定义标记实现用例筛选的步骤如下:

  1. 先在 pytest.ini 注册标记

    [pytest]

    markers =
    api: 接口测试
    web: UI测试
    ut: 单元测试

  1. 使用@pytest.mark.<your_marker>标记用例

  2. 筛选执行

bash 复制代码
pytest -m api  # 只执行api接口用例

6.2 框架内置标记

框架内置标记无需手动注册,按照框架要求使用即可。不同的标记,可以增加不同的特殊效果。

6.2.1 parametrize 参数化

@pytest.mark.parametrize 可使用不同的输入数据多次执行相同的测试逻辑,以扩大测试覆盖范围。

python 复制代码
import pytest

@pytest.mark.parametrize("username, password, expected", [
    ("admin", "secret", True),  # 有效凭证
    ("admin", "wrong", False),  # 无效密码 (也属于核心流程)
])
def test_admin_login(username, password, expected):
    result = login(username, password)
    assert result == expected

上述代码中,test_admin_login 测试函数被参数化,使用两组数据覆盖了管理员登录的成功和失败场景。

在第7章节,数据驱动测试我们还会使用到该注解。

6.2.2 skip 无条件跳过

使用 @pytest.mark.skip 可以无条件跳过测试函数。

python 复制代码
import pytest

@pytest.mark.skip(reason="功能尚未实现,等待后续开发")
def test_new_feature():
    # 这个测试会被跳过
    assert True

@pytest.mark.skip
def test_deprecated_function():
    # 这个测试也会被跳过,没有提供原因
    assert False

运行结果示例:

复制代码
 pytest -r s .\test_mark_skip.py  # 只运行某个py文件,同时显示跳过的详细信息

6.2.3 skipif 有条件跳过

使用 @pytest.mark.skipif 可以根据条件跳过测试。

python 复制代码
import pytest
import sys

# 根据Python版本跳过
@pytest.mark.skipif(sys.version_info < (3, 8), 
                    reason="需要Python 3.8或更高版本")
def test_python38_feature():
    # 只在Python 3.8+上运行
    assert True

# 根据操作系统跳过
@pytest.mark.skipif(sys.platform == "win32", 
                    reason="Windows系统不支持此功能")
def test_unix_only_feature():
    # 只在Unix-like系统上运行
    assert True

# 根据外部依赖跳过
pytest.importorskip("requests", reason="需要requests库")

@pytest.mark.skipif(not pytest.importorskip("numpy", reason="需要numpy库"),
                    reason="numpy不可用")
def test_numpy_functionality():
    import numpy as np
    assert np.array([1, 2, 3]).sum() == 6

# 自定义条件
def is_development_environment():
    import os
    return os.getenv("ENV") == "development"

@pytest.mark.skipif(not is_development_environment(),
                    reason="仅在开发环境中运行")
def test_development_only():
    assert True

6.2.4 xfail 预期失败

使用 @pytest.mark.xfail标记预期失败的测试。

python 复制代码
import pytest

# 预期失败但没有提供原因
@pytest.mark.xfail
def test_known_bug():
    assert 1 + 1 == 3  # 已知的bug,预期会失败

# 预期失败并说明原因
@pytest.mark.xfail(reason="已知bug:修复中,issue #123")
def test_buggy_function():
    # 这个函数有已知问题,预期会失败
    result = calculate_something()
    assert result == expected_value

def calculate_something():
    return 42

# 预期失败但如果通过了则视为失败(严格模式)
@pytest.mark.xfail(strict=True, reason="这个bug肯定没修复")
def test_strict_xfail():
    assert False  # 如果这个测试意外通过了,会被标记为失败

# 条件性预期失败
@pytest.mark.xfail(sys.version_info < (3, 9), 
                   reason="Python 3.9以下版本有兼容性问题")
def test_version_specific_feature():
    # 在某些版本下预期失败
    assert True

# 在测试函数内部动态标记为预期失败
def test_runtime_xfail():
    try:
        result = risky_operation()
        assert result is not None
    except NotImplementedError:
        pytest.xfail("功能尚未实现")

def risky_operation():
    raise NotImplementedError("还在开发中")

运行结果示例:

复制代码
collected 4 items

test_example.py xxxx                                              [100%]

4 xfailed in 0.02s

6.2.5 usefixtures:使用fixtures

使用 @pytest.mark.usefixtures为测试函数指定fixtures,无需在函数参数中声明。以下是代码示例,在第8章节夹具fixture中,将会着重介绍。

python 复制代码
import pytest

# 定义一些fixtures
@pytest.fixture
def database():
    print("\n设置数据库连接")
    yield "database_connection"
    print("清理数据库连接")

@pytest.fixture
def authenticated_user():
    print("\n创建认证用户")
    yield {"username": "testuser", "id": 123}
    print("清理用户数据")

@pytest.fixture
def temp_file():
    import tempfile
    import os
    
    fd, path = tempfile.mkstemp()
    os.close(fd)
    
    yield path
    
    os.unlink(path)

# 使用单个fixture
@pytest.mark.usefixtures("database")
def test_database_operations():
    # 不需要在参数中声明database fixture
    # 但可以访问其他fixture
    assert True

# 使用多个fixtures
@pytest.mark.usefixtures("database", "authenticated_user")
def test_user_operations():
    # 同时使用database和authenticated_user fixtures
    assert True

# 在类级别使用fixtures
@pytest.mark.usefixtures("temp_file")
class TestFileOperations:
    
    def test_read_file(self):
        # 所有测试方法都会使用temp_file fixture
        assert True
    
    def test_write_file(self):
        assert True

# 在模块级别使用fixtures(在conftest.py中或文件顶部)
pytestmark = pytest.mark.usefixtures("database")

def test_module_level_test():
    # 这个测试也会使用database fixture
    assert True

# 混合使用:参数fixtures和标记fixtures
def test_mixed_fixtures(authenticated_user, temp_file):
    # authenticated_user通过参数传入
    # temp_file通过usefixtures标记使用
    assert authenticated_user["username"] == "testuser"

# 也可以在测试函数内部使用其他fixtures
@pytest.mark.usefixtures("database")
def test_with_additional_fixture(authenticated_user):
    # database通过标记使用,authenticated_user通过参数使用
    assert True

7 数据驱动测试

数据驱动测试 = 参数化测试 + 数据文件,即根据数据文件的内容,动态决定用例的数量、内容。会用到标记中的 @pytest.mark.parametrize 。以下例子将会以一个csv文件格式,演示代码示例。

  1. 创建一个数据文件,例如 data.csv

    a,b,c
    1,1,2
    2,3,5
    3,3,6
    4,4,7

  2. 编写读取csv文件的方法

python 复制代码
import csv


def read_csv(path):
    f = open(path)
    try:
        reader = csv.reader(f)
        data = list(reader)[1:]  # 跳过标题行
        return data
    finally:
        f.close()
  
  1. 编写用例
python 复制代码
import pytest
from get_csv import read_csv


def add(a, b):
    return int(a) + int(b)


@pytest.mark.parametrize(
    "a, b, c",
    read_csv("data.csv")
)
def test_add(a, b, c):
    res = add(a, b)
    assert res == int(c)
  1. 执行用例,查看结果,csv的4组参数,都被正确执行

8 夹具fixture

夹具,即在用例执行之前或者执行之后,自动运行代码,有如下几种场景示例:

  • 之前:加密参数 / 之后:解密结果
  • 之前:启动浏览器 / 之后:关闭浏览器
  • 之前:构造数据 / 之后:删除数据

8.1 如何创建fixture

  1. 创建方法/函数
  2. 添加装饰器 @pytest.fixture
  3. 添加 yield 关键字
python 复制代码
@pytest.fixture
def method():
    # 前置操作
    yield  # 开始执行用例
    # 后置操作
    

8.2 如何使用fixture

使用fixture有两种方式

方式一:在用例的参数列表中,加入 fixture 的方法名即可

python 复制代码
import pytest


@pytest.fixture
def f():
    # 前置操作
    yield  # 开始执行用例
    # 后置操作


def test_xxx(f):
    assert True
    

方式二:使用 @pytest.mark.usefixtures 为测试函数指定fixtures,无需在函数参数中声明

python 复制代码
import pytest


@pytest.fixture
def f():
    # 前置操作
    yield  # 开始执行用例
    # 后置操作


@pytest.mark.usefixtures('f')
def test_xxx():
    assert True
    

8.3 fixture高级用法

1.自动使用

当多个用例都需要执行fixture时,可以不必每个用例都显示声明usefixtures,可以在编写fixture的时候通过autouse参数实现,示例代码如下:

python 复制代码
from datetime import datetime
import pytest


@pytest.fixture(autouse=True)
def f():
    # 前置操作
    print(datetime.now(), "用例开始执行")
    yield
    # 后置操作
    print(datetime.now(), "用例执行完毕")


def test_f1():
    assert True


def test_f2():
    assert True

2.依赖使用

fixture不仅仅能被用例使用,也可被fixture依赖使用,示例代码如下:

python 复制代码
import pytest


@pytest.fixture()
def process():
    print("处理数据完成")


@pytest.fixture()
def f(process):
    print("用例执行前")
    yield
    print("用例执行后")


@pytest.mark.usefixtures('f')
def test_f():
    assert True
    


3.返回内容

定义的fixture可以有返回内容,被测试用例使用

(1)基本使用方式:

  • 将fixture名称作为测试函数的参数
  • pytest会自动注入fixture的返回值
  • 可以直接在测试函数中使用fixture返回的数据或对象

(2)最佳实践:

  • fixture应该返回具体的、可用的数据或对象
  • 避免在fixture中执行复杂的业务逻辑
  • 使用yield而不是return时,yield后面的代码会在测试结束后执行
  • 可以在测试函数中组合使用多个fixture

示例代码如下:

python 复制代码
import pytest


@pytest.fixture
def sample_data():
    """返回测试数据的fixture"""
    return {
        "username": "test_user",
        "password": "test123",
        "email": "test@example.com"
    }


@pytest.fixture
def calculator():
    """返回简单计算器对象的fixture"""
    class SimpleCalculator:
        def add(self, a, b):
            return a + b
        
        def subtract(self, a, b):
            return a - b
        
        def multiply(self, a, b):
            return a * b
        
        def divide(self, a, b):
            if b == 0:
                raise ValueError("除数不能为零")
            return a / b
    
    return SimpleCalculator()


@pytest.fixture
def user_list():
    """返回用户列表的fixture"""
    return [
        {"id": 1, "name": "张三", "age": 25},
        {"id": 2, "name": "李四", "age": 30},
        {"id": 3, "name": "王五", "age": 28}
    ]


@pytest.fixture
def database_connection():
    """模拟数据库连接的fixture"""
    class MockDatabase:
        def __init__(self):
            self.connected = True
            self.data = {}
        
        def execute(self, query):
            return f"执行查询: {query}"
        
        def close(self):
            self.connected = False
    
    conn = MockDatabase()
    yield conn  # 使用yield,测试结束后会执行清理
    conn.close()


# 测试函数使用fixture返回的数据
def test_sample_data_fixture(sample_data):
    """测试sample_data fixture返回的数据"""
    assert sample_data["username"] == "test_user"
    assert sample_data["password"] == "test123"
    assert sample_data["email"] == "test@example.com"
    print(f"用户名: {sample_data['username']}")


def test_calculator_fixture(calculator):
    """测试calculator fixture返回的计算器对象"""
    result_add = calculator.add(5, 3)
    assert result_add == 8
    
    result_subtract = calculator.subtract(10, 4)
    assert result_subtract == 6
    
    result_multiply = calculator.multiply(3, 7)
    assert result_multiply == 21
    
    result_divide = calculator.divide(15, 3)
    assert result_divide == 5.0
    
    # 测试除零异常
    with pytest.raises(ValueError, match="除数不能为零"):
        calculator.divide(10, 0)


def test_user_list_fixture(user_list):
    """测试user_list fixture返回的用户列表"""
    assert len(user_list) == 3
    assert user_list[0]["name"] == "张三"
    assert user_list[1]["age"] == 30
    assert user_list[2]["id"] == 3
    
    # 测试查找功能
    user = next(u for u in user_list if u["name"] == "李四")
    assert user["age"] == 30


def test_database_connection_fixture(database_connection):
    """测试database_connection fixture返回的数据库连接"""
    assert database_connection.connected == True
    
    result = database_connection.execute("SELECT * FROM users")
    assert "SELECT * FROM users" in result
    
    print(f"数据库查询结果: {result}")


# 测试多个fixture的组合使用
def test_multiple_fixtures(sample_data, calculator, user_list):
    """测试多个fixture的组合使用"""
    # 使用sample_data中的数据进行计算
    age = sample_data["password"][-3:]  # 从密码中提取数字"123"
    age_int = int(age)
    
    # 使用calculator进行计算
    result = calculator.add(age_int, len(user_list))
    assert result == 126  # 123 + 3
    
    print(f"计算结果: {result}")


@pytest.fixture
def config_data():
    """返回配置数据的fixture"""
    return {
        "database": {
            "host": "localhost",
            "port": 5432,
            "name": "test_db"
        },
        "api": {
            "base_url": "https://api.example.com",
            "timeout": 30,
            "retries": 3
        },
        "debug": True
    }


def test_config_fixture(config_data):
    """测试配置数据fixture"""
    assert config_data["database"]["host"] == "localhost"
    assert config_data["database"]["port"] == 5432
    assert config_data["api"]["base_url"] == "https://api.example.com"
    assert config_data["debug"] == True
    # 测试嵌套数据访问
    db_config = config_data["database"]
    assert f"{db_config['host']}:{db_config['port']}" == "localhost:5432"


4.范围共享

Fixture是pytest提供的一种自动化机制,用于在测试用例执行前后运行特定代码。在UI自动化测试中,如果每个用例都单独执行打开和关闭浏览器的操作,会造成巨大的性能开销。通过将fixture的scope配置为session级别,可以在整个测试会话中共享同一个浏览器实例,所有测试用例复用该前置和后置操作,从而显著提升测试效率。

(1) 作用域类型:

  • function(默认):每个测试函数执行一次
  • class:每个测试类执行一次
  • module:每个模块执行一次
  • package:每个包执行一次
  • session:整个测试会话执行一次

(2) 使用方式:

python 复制代码
@pytest.fixture(scope="作用域类型")
def fixture_name():
    return 数据或对象

示例代码如下:

python 复制代码
import pytest


# Function作用域(默认)- 每个测试函数都会重新执行
@pytest.fixture(scope="function")
def function_data():
    """Function作用域的fixture - 每个测试函数都创建新实例"""
    print("\n创建function_data")
    return {"id": 1, "name": "function测试"}


# Class作用域 - 每个测试类执行一次
@pytest.fixture(scope="class")
def class_data():
    """Class作用域的fixture - 每个测试类执行一次"""
    print("\n创建class_data")
    return {"id": 2, "name": "class测试"}


# Module作用域 - 每个模块执行一次
@pytest.fixture(scope="module")
def module_data():
    """Module作用域的fixture - 每个模块执行一次"""
    print("\n创建module_data")
    return {"id": 3, "name": "module测试"}


# Session作用域 - 整个测试会话执行一次
@pytest.fixture(scope="session")
def session_data():
    """Session作用域的fixture - 整个测试会话执行一次"""
    print("\n创建session_data")
    return {"id": 4, "name": "session测试"}


# 测试function作用域
def test_function_scope_1(function_data):
    """测试function作用域 fixture"""
    print(f"test_function_scope_1: {function_data}")
    assert function_data["id"] == 1


def test_function_scope_2(function_data):
    """测试function作用域 fixture - 会重新创建"""
    print(f"test_function_scope_2: {function_data}")
    assert function_data["id"] == 1


# 测试class作用域
class TestClassScope:
    def test_class_scope_1(self, class_data):
        """测试class作用域 fixture"""
        print(f"test_class_scope_1: {class_data}")
        assert class_data["id"] == 2
    
    def test_class_scope_2(self, class_data):
        """测试class作用域 fixture - 共享同一实例"""
        print(f"test_class_scope_2: {class_data}")
        assert class_data["id"] == 2


class TestClassScope2:
    def test_class_scope_3(self, class_data):
        """测试class作用域 fixture - 新类会重新创建"""
        print(f"test_class_scope_3: {class_data}")
        assert class_data["id"] == 2


# 测试module作用域
def test_module_scope_1(module_data):
    """测试module作用域 fixture"""
    print(f"test_module_scope_1: {module_data}")
    assert module_data["id"] == 3


def test_module_scope_2(module_data):
    """测试module作用域 fixture - 共享同一实例"""
    print(f"test_module_scope_2: {module_data}")
    assert module_data["id"] == 3


# 测试session作用域
def test_session_scope_1(session_data):
    """测试session作用域 fixture"""
    print(f"test_session_scope_1: {session_data}")
    assert session_data["id"] == 4


def test_session_scope_2(session_data):
    """测试session作用域 fixture - 共享同一实例"""
    print(f"test_session_scope_2: {session_data}")
    assert session_data["id"] == 4


# 混合作用域测试
class TestMixedScopes:
    def test_mixed_scopes(self, function_data, class_data, module_data, session_data):
        """测试混合作用域 fixture"""
        print(f"混合作用域测试:")
        print(f"  function: {function_data}")
        print(f"  class: {class_data}")
        print(f"  module: {module_data}")
        print(f"  session: {session_data}")
        
        assert function_data["id"] == 1
        assert class_data["id"] == 2
        assert module_data["id"] == 3
        assert session_data["id"] == 4


# Package作用域示例(需要包结构)
@pytest.fixture(scope="package")
def package_data():
    """Package作用域的fixture - 每个包执行一次"""
    print("\n创建package_data")
    return {"id": 5, "name": "package测试"}


def test_package_scope(package_data):
    """测试package作用域 fixture"""
    print(f"test_package_scope: {package_data}")
    assert package_data["id"] == 5

实际使用中,作用域会被命名空间限制,例如在同一目录下不同的py文件定义的fixture可能无法被找到。因此,在实际开发中,我们常常引入第三命名空间,即新建一个conftest.py文件来统一声明fixture


写在最后

本文已被专栏 测试开发知识库 收录,欢迎 点击订阅专栏

以上便是本文的全部内容啦!创作不易,如果你有任何问题,欢迎私信,感谢您的支持!

相关推荐
dagouaofei5 小时前
文档生成PPT到底快不快?PDF转PPT工具实测分析
python·pdf·powerpoint
玖日大大5 小时前
TensorFlow 深度解析:从基础到实战的全维度指南
人工智能·python·tensorflow
不拱地的猪5 小时前
Matplotlib 的字体参数设置方法(MAC OSX)
python·mac·matplotlib·字体设置·文中显示中文
free-elcmacom5 小时前
机器学习高阶教程<3>统计学习理论进阶
人工智能·python·机器学习·统计学习理论
zuoyou-HPU5 小时前
ChatGLM4 的 tokenizer 配置文件解析
python·大模型·glm
keineahnung23455 小时前
從 SymBool 到 SymFloat:PyTorch user magic methods 如何支持符號形狀運算?
人工智能·pytorch·python·深度学习
_妲己6 小时前
SD的细分功能包括重绘,图像处理、放大等扩散模型应用
人工智能·python·深度学习·机器学习·stable diffusion·comfyui·ai工作流
暗之星瞳6 小时前
python爬虫学习(搜索)
爬虫·python·学习
一只乔哇噻6 小时前
java后端工程师+AI大模型开发进修ing(研一版‖day63)
java·开发语言·人工智能·python·语言模型