一、高效用例管理(提升测试效率)

1. 用例标记与筛选(精准控制执行范围)

基础的@pytest.mark可以自定义标记,实现按「模块 / 优先级 / 环境」筛选执行:

import pytest

# 1. 定义自定义标记(需在pytest.ini中注册,否则会报警告)
# 先在项目根目录创建pytest.ini文件,内容:
# [pytest]
# markers =
#     smoke: 冒烟测试用例(核心功能)
#     dev: 开发环境专用
#     prod: 生产环境专用
#     high: 高优先级
#     low: 低优先级

# 2. 给用例打标记
@pytest.mark.smoke
@pytest.mark.high
def test_login():
    assert True  # 模拟登录功能(核心冒烟用例)

@pytest.mark.dev
@pytest.mark.low
def test_data_debug():
    assert True  # 开发环境调试用例

@pytest.mark.prod
@pytest.mark.high
def test_pay():
    assert True  # 支付功能(生产高优)

# 3. 运行时筛选标记(终端命令)
"""
pytest -v -m smoke          # 只运行冒烟用例
pytest -v -m "high and prod" # 只运行生产环境高优用例
pytest -v -m "not dev"      # 排除开发环境用例
"""
2. 用例依赖(控制执行顺序 / 跳过依赖失败的用例)

使用pytest-dependency插件实现用例依赖(先安装:pip install pytest-dependency):

import pytest

# 标记依赖关系:test_order_pay依赖test_order_create
@pytest.mark.dependency()
def test_order_create():
    assert True  # 假设创建订单成功

@pytest.mark.dependency(depends=["test_order_create"])
def test_order_pay():
    assert True  # 支付用例,仅当创建订单成功才执行

# 如果test_order_create失败,test_order_pay会自动跳过(标记为skipped)
3. 失败重试(解决偶发失败的用例)

使用pytest-rerunfailures插件实现失败重试(先安装:pip install pytest-rerunfailures):

import pytest
import random

# 模拟偶发失败的用例(比如接口超时、网络抖动)
@pytest.mark.flaky(reruns=3, reruns_delay=2)  # 失败重试3次,每次间隔2秒
def test_rerun_demo():
    # 随机返回True/False,模拟偶发失败
    assert random.choice([True, False])

# 终端运行(也可通过命令行指定重试):
# pytest -v --reruns 3 --reruns-delay 2 test_demo.py

二、测试结果增强(可视化 / 可分析)

1. 生成 HTML 测试报告(直观展示结果)

使用pytest-html插件生成美观的 HTML 报告(先安装:pip install pytest-html):

# 运行命令(指定报告保存路径)
pytest -v --html=report.html --self-contained-html test_demo.py
  • --html=report.html:生成名为 report.html 的报告
  • --self-contained-html:将 CSS / 图片嵌入报告(避免打开时样式丢失)
  • 运行后打开 report.html,可看到用例通过率、失败详情、执行时间等。
2. 集成 Allure 报告(专业级测试报告)

Allure 是工业级测试报告工具,支持步骤展示、截图、日志等(步骤稍多,但效果更好):

步骤 1:安装依赖
# 安装pytest-allure-adaptor
pip install allure-pytest
# 下载Allure命令行工具(需配置环境变量):https://github.com/allure-framework/allure2/releases
步骤 2:编写带 Allure 标记的用例
import pytest
import allure

@allure.feature("用户模块")  # 大功能模块
@allure.story("用户登录")    # 子功能
@allure.severity(allure.severity_level.CRITICAL)  # 优先级:CRITICAL > HIGH > MEDIUM > LOW
def test_login_success():
    with allure.step("步骤1:输入用户名密码"):
        username = "test"
        password = "123456"
    with allure.step("步骤2:点击登录按钮"):
        pass
    with allure.step("步骤3:验证登录结果"):
        assert True

@allure.feature("用户模块")
@allure.story("用户登出")
def test_logout():
    assert True
步骤 3:生成并查看 Allure 报告
# 生成Allure原始数据
pytest -v --alluredir=./allure-results test_demo.py
# 启动本地服务查看报告
allure serve ./allure-results

三、高级功能(适配复杂场景)

1. 夹具(Fixture)进阶用法

Fixture 是 pytest 的核心,除了基础的前置后置,还有这些实用技巧:

(1)Fixture 参数化
import pytest

# 参数化夹具:返回不同的测试环境
@pytest.fixture(params=["dev", "test", "prod"])
def env(request):
    return request.param  # request.param获取当前参数值

# 使用参数化夹具:会自动生成3个用例(分别对应dev/test/prod)
def test_env_check(env):
    print(f"当前测试环境:{env}")
    assert env in ["dev", "test", "prod"]
(2)Fixture 作用域(控制生效范围)
import pytest

# scope可选:function(默认,每个函数)、class(每个类)、module(每个文件)、session(整个测试会话)
@pytest.fixture(scope="session")
def init_db():
    print("\n会话开始:初始化数据库连接")
    yield  # 前置操作
    print("\n会话结束:关闭数据库连接")

# 每个测试函数都会执行(scope=function)
@pytest.fixture
def init_data():
    print("\n函数开始:初始化测试数据")
    yield [1,2,3]
    print("\n函数结束:清理测试数据")
(3)Fixture 依赖与共享

创建conftest.py文件(pytest 自动识别,无需导入),存放全局 Fixture:

# conftest.py(项目根目录)
import pytest

@pytest.fixture(scope="session")
def global_config():
    return {"base_url": "https://api.test.com", "timeout": 10}

# 任意测试文件中直接使用
def test_use_global_config(global_config):
    assert global_config["timeout"] == 10
2. 模拟外部依赖(Mock)

使用unittest.mock(Python 内置)或pytest-mock插件,模拟接口、数据库等外部依赖,避免测试受外部环境影响:

import pytest
from unittest.mock import Mock, patch

# 模拟一个外部接口调用函数
def get_user_info(user_id):
    # 实际场景中会调用真实接口
    import requests
    resp = requests.get(f"https://api.test.com/user/{user_id}")
    return resp.json()

# 使用mock模拟接口返回
def test_get_user_info(mocker):  # pytest-mock提供的mocker夹具
    # 模拟requests.get方法,返回自定义结果
    mock_get = mocker.patch("requests.get")
    mock_get.return_value.json.return_value = {"id": 1, "name": "test"}
    
    # 调用被测试函数(实际不会发真实请求)
    result = get_user_info(1)
    assert result["name"] == "test"
    # 验证mock被调用过
    mock_get.assert_called_once_with("https://api.test.com/user/1")
3. 自定义测试收集规则

如果不想遵循test_开头的命名规则,可以自定义收集逻辑:

# conftest.py
def pytest_collection_modifyitems(items):
    """修改用例收集规则:识别以check_开头的函数作为测试用例"""
    for item in items:
        # 将check_开头的函数标记为测试用例
        if item.name.startswith("check_"):
            item.add_marker(pytest.mark.testcase)
    # 也可以修改用例执行顺序
    items.sort(key=lambda x: x.name)

# 测试文件中
def check_login():
    assert True  # 会被识别为测试用例

总结

  1. 效率提升:掌握「标记筛选 + 失败重试 + 用例依赖」,能精准控制用例执行,减少无效操作;
  2. 结果分析pytest-html快速生成报告,Allure 适合专业测试场景,按需选择;
  3. 复杂场景适配:Fixture 进阶(参数化 / 作用域 / 全局共享)+ Mock 模拟外部依赖,是解决实际问题的核心。
Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐