Pytest插件之pytest-xdist分布式执行用例

一、背景

在现代软件开发中,自动化测试是保证代码质量的关键一环。随着项目规模的扩大,测试套件的执行时间可能变得难以接受。pytest-xdist 是一个 Pytest 插件,它通过并发和分布式测试执行,帮助我们显著提高测试效率。

pytest-xdist 是一个 Pytest 插件,用于并行执行测试,支持跨多个CPU核心或通过网络跨多台机器运行测试。这使得我们可以在更短的时间内完成更多的测试,加速CI/CD流程。

二、安装

  • 确保已经安装了pytest。如果没有安装,可以使用以下命令进行安装:
   pip install pytest
  • 安装pytest-xdist插件:
   pip install pytest-xdist

三、原理

pytest-xdist的工作原理主要包括以下几个方面:

  1. 解析命令行参数:pytest-xdist会解析命令行参数,获取用户指定的分发模式、进程数、主机列表等信息。
  2. 加载测试用例:pytest-xdist会加载所有的pytest测试用例,并将它们分发给多个进程或计算机上的worker进行并行执行。
  3. 分布式执行:pytest-xdist不仅可以在多进程上运行测试,还可以在多个计算机上进行分布式测试。每个进程或worker负责执行一部分测试用例,从而大大提高测试效率

四、命令行参数说明

1、参数说明

pytest-xdist 提供了多个命令行参数来控制并发和分布式测试的行为:

  • -n--numprocesses:设置并发执行的进程数或线程数。
  • --dist:定义并发模式,可选的模式有 loadscope, loadfile, loadclass, loadmodule, each
  • --tx--executor:定义使用的执行器,如 thread, process, forked, subprocess

2、分发策略

pytest-xdist提供了多种参数来控制测试的执行方式和分发策略:

  • --dist=loadscope 将按照同一个作用域方法来分组(按照模块或类进行分组),然后将每个测试组发给可以执行的worker,确保同一个组的测试用例在同一个进程中执行
  • --dist=loadfile 按照同一个文件名来分组,然后将每个测试组发给可以执行的worker,确保同一个组的测试用例在同一个进程中执行
  • --dist=each 是将每个用例,分别发给所有的执行器worker,相当于开了几个执行器worker,同一个用例就执行几遍
  • --dist=load 默认选项,将待运行的用例随机发给可用的执行器worker,不保证执行顺序。

3、执行器

--tx(或其等价的 --executor)参数让你定义使用的执行器类型。这个参数对于决定如何在不同的工作进程中执行测试非常有用。

  • thread:在每个工作进程中使用线程执行测试。

  • process:在每个工作进程中使用多个进程执行测试(默认)。

  • forked:在每个工作进程中使用 multiprocessing 模块的 Process 类。

  • subprocess:在子进程中执行测试,适用于某些需要隔离环境的场景。

  • 示例:使用线程执行器。

    pytest --tx=thread
    

4、命令用法

  • 使用4个进程并发执行测试:

    pytest -n 4
    
  • 每个测试文件作为一个独立的进程执行:

    pytest -n auto --dist=loadfile
    
  • 使用远程执行器(例如,使用 pytest-xdistsubprocess 模式):

    pytest --tx subprocess
    

五、配置文件参数

除了命令行参数,pytest-xdist 的配置也可以在 pytest.inipyproject.toml 文件中设置:

1、pytest.ini 示例

[pytest]
addopts = -n 4 --dist=loadfile

2、pyproject.toml 示例

[tool.pytest]
addopts = "--n 4 --dist=loadfile"

3、参考示例代码

假设我们有以下测试文件结构:

/tests
|-- test_example1.py
|-- test_example2.py

每个文件包含若干独立的测试用例。

test_example1.py 示例代码

def test_example1_pass():
    assert 1 == 1

def test_example1_fail():
    assert 1 == 2

test_example2.py 示例代码

import time

def test_example2_slow():
    time.sleep(2)
    assert True

要并发执行这些测试,你可以使用以下命令:

复制
pytest -n 4

六、使用场景

1、如何保持session执行一次

当使用 pytest-xdist 插件进行并行测试执行时,确保 scope="session" 的 fixture 只执行一次可能会有些复杂。

由于并行执行的本性,多个进程可能同时尝试初始化这样的 fixture。为了处理这个问题,你可以采取以下策略:使用 Global Lock

使用文件锁或分布式锁来确保初始化操作只在一个进程中执行一次。

import pytest
from filelock import FileLock


lock = FileLock("test_init.lock")

def initialize():
    with lock:
        # 放置你的初始化代码,例如登录
        # 确保这里的代码是幂等的
        # web ui自动化,声明一个driver,再返回driver
		# 或者接口自动化,先执行登录请求操作,再返回token
        pass


@pytest.fixture(scope="session")
def test_setup():
    initialize()
    # 其他 setup 逻辑
    yield

2、ssh和socket远程通信

pytest-xdist 插件确实支持通过网络进行分布式测试执行,它可以通过 SSH (Secure Shell) 或者 socket 来进行 master 和 worker 之间的远程通信。以下是如何使用这两种方式实现远程通信的基本步骤:

  • 使用 SSH 进行远程通信
  1. 安装 paramikopytest-xdist 使用 paramiko 库来处理 SSH 连接,因此你需要安装它。

    pip install paramiko
    
  2. 配置 SSH 密钥:为了无密码登录到远程机器,你需要设置 SSH 密钥认证。

    ssh-keygen  # 生成 SSH 密钥对
    ssh-copy-id user@remote-host  # 复制公钥到远程主机
    
  3. 使用 --tx 参数:在运行 pytest 命令时,使用 --tx 参数并指定 ssh 作为传输方式。

    pytest --tx ssh=[user@remote-host] -n 2
    

    这里 [user@remote-host] 是远程主机的 SSH 访问地址,-n 2 表示使用两个并发进程。

  • 使用 Socket 进行远程通信
  1. 确定 master 和 worker 的地址和端口:你需要决定用于通信的 IP 地址和端口号。

  2. 启动 worker:在远程机器上,使用 pytest 的 --tx 参数和 socket 传输方式启动 worker。

    pytest --tx socket=<master-ip>:<port> --n 2
    

    这里 <master-ip> 是 master 节点的 IP 地址,<port> 是用于通信的端口号。

  3. 配置 master:在 master 节点上运行 pytest 时,同样使用 --tx 参数,但不需要指定远程地址。

    pytest --tx socket=<port> -n 2
    

假设你有一个 master 节点和一个 worker 节点,master 节点的 IP 是 192.168.1.100,worker 节点的 IP 是 192.168.1.101,你希望在这两个节点上并发执行测试。

  • 在 worker 节点上(192.168.1.101),运行以下命令:

    pytest --tx socket=192.168.1.100:8888 --n 2
    
  • 在 master 节点上(192.168.1.100),运行以下命令:

    pytest --tx socket=8888 -n 2
    

注意事项

  • 确保网络配置允许 master 和 worker 节点之间的通信。
  • 如果在云环境或使用了防火墙,确保相应的端口已开放。
  • 使用 SSH 方式时,确保 SSH 密钥已正确设置,并且无密码登录是可行的。

七、参考

1、https://developer.moduyun.com/article/fb2ae78e-2e4f-4972-8f5d-b066ff163edb.html

posted @ 2024-06-03 13:30  xyztank  阅读(418)  评论(0编辑  收藏  举报