侧边栏壁纸
博主头像
一朵云的博客博主等级

拥抱生活,向阳而生。

  • 累计撰写 108 篇文章
  • 累计创建 28 个标签
  • 累计收到 7 条评论

目 录CONTENT

文章目录

pytest -- pytest-xdist插件的介绍和使用

一朵云
2023-12-13 / 0 评论 / 0 点赞 / 240 阅读 / 6714 字

pytest-xdist 插件的介绍和使用

简介:

pytest-xdist 是非常重要的插件。通过多进程方式,并行执行测试用例来显著提升测试效率(充分利用多核 CPU 资源,加快整体测试执行速度)。特别适合那些测试用例较多、耗时较长的项目。

准备:

安装插件:

pip install pytest-xdist

运行方式:

1、自动使用所有 CPU 核心

pytest -n auto
  • -n auto:自动检测并使用与 CPU 核心数相同的进程数

2、指定使用固定数量的进程

pytest -n 4
  • 使用 4 个进程并行执行测试

3、配置 pytest.ini 以默认启用 -n auto(推荐)

pytest.ini 中使用 addopts 选项来设置默认参数。

[pytest]
addopts = -v -n auto

注意事项:

✅ 测试之间必须独立!

  • 如果多个测试共享资源(如数据库、文件、全局变量),可能会导致冲突
  • 建议使用 fixture 创建隔离的测试环境

✅ 日志和输出可能乱序

  • 并行执行时,不同进程的输出会混在一起
  • 可使用 pytest --capture=no 或生成 HTML 报告查看详细结果

✅ 某些插件不兼容

  • 有些插件(如 pytest-cov)需要特别处理才能正确统计覆盖率
  • 使用 --no-cov 可临时禁用覆盖率统计

示例使用:

全局变量隔离:

使用全局变量时,需使用 @pytest.fixture避免用例间冲突

import pytest


@pytest.fixture
def isolated_data():
    return []


def test_1(isolated_data):
    isolated_data.append(1)
    assert isolated_data == [1]


def test_2(isolated_data):
    isolated_data.append(2)
    assert isolated_data == [2]

image-wnqp.png

数据库隔离:

MySQL + pytest-xdist

1、使用 fixture 提供隔离的数据库连接。

# conftest.py

import pytest
import mysql.connector
from mysql.connector import errorcode
import uuid

@pytest.fixture(scope="session")
def mysql_db():
    # 连接 MySQL 服务器(注意不要连接具体数据库)
    conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password"
    )
    cursor = conn.cursor()

    # 生成唯一数据库名(使用 UUID)
    db_name = f"testdb_{uuid.uuid4().hex}"
  
    try:
        cursor.execute(f"CREATE DATABASE {db_name}")
        conn.commit()
    finally:
        cursor.close()
        conn.close()

    # 新建连接到新数据库
    db_conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password",
        database=db_name
    )

    yield db_conn

    # 清理:删除测试数据库
    db_conn.close()
    drop_conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password"
    )
    drop_cursor = drop_conn.cursor()
    drop_cursor.execute(f"DROP DATABASE IF EXISTS {db_name}")
    drop_conn.commit()
    drop_cursor.close()
    drop_conn.close()

测试中使用隔离的数据库连接:

# test_mysql.py

def test_insert_data(mysql_db):
    cursor = mysql_db.cursor()
    cursor.execute("CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(255))")
    cursor.execute("INSERT INTO test_table VALUES (1, 'Alice')")
    mysql_db.commit()

    cursor.execute("SELECT * FROM test_table")
    result = cursor.fetchall()
    assert result == [(1, 'Alice')]

2、使用事务隔离(推荐)

在每个测试中使用事务,并在测试结束后回滚,避免污染数据。

使用 session 级数据库连接 + function 级事务,兼顾性能与隔离性。

# conftest.py

import pytest
import mysql.connector
from mysql.connector import errorcode
import uuid

@pytest.fixture(scope="session")
def mysql_db():
    # 连接 MySQL 服务器(注意不要连接具体数据库)
    conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password"
    )
    cursor = conn.cursor()

    # 生成唯一数据库名(使用 UUID)
    db_name = f"testdb_{uuid.uuid4().hex}"
  
    try:
        cursor.execute(f"CREATE DATABASE {db_name}")
        conn.commit()
    finally:
        cursor.close()
        conn.close()

    # 新建连接到新数据库
    db_conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password",
        database=db_name
    )

    yield db_conn

    # 清理:删除测试数据库
    db_conn.close()
    drop_conn = mysql.connector.connect(
        host="localhost",
        user="root",
        password="your_password"
    )
    drop_cursor = drop_conn.cursor()
    drop_cursor.execute(f"DROP DATABASE IF EXISTS {db_name}")
    drop_conn.commit()
    drop_cursor.close()
    drop_conn.close()


@pytest.fixture(scope="function")
def mysql_cursor(mysql_db):
    cursor = mysql_db.cursor()
    mysql_db.start_transaction()
    yield cursor
    mysql_db.rollback()
    cursor.close()

然后在测试中使用:

def test_with_transaction(mysql_cursor):
    mysql_cursor.execute("CREATE TABLE test_table (id INT PRIMARY KEY, name VARCHAR(255))")
    mysql_cursor.execute("INSERT INTO test_table VALUES (1, 'Alice')")

    mysql_cursor.execute("SELECT * FROM test_table")
    result = mysql_cursor.fetchall()
    assert result == [(1, 'Alice')]

所有操作在事务中进行,测试结束后自动回滚,数据库干净无污染。

0

评论区