测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

这篇具有很好参考价值的文章主要介绍了测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录:导读

前言:

多进程执行用例之pytest-xdist

pytest-xdist分布式测试的原理:

pytest-xdist分布式测试的流程:

多线程执行用例之pytest-parallel

常用参数配置

pytest-parallel与pytest-xdist对比说明:

结语


测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

前言:

大家好!我是不二。

相信很多测试工程师都会遇到一个问题,那就是测试用例的执行速度不够快。对于一个庞大的项目来说,测试用例数量可能会非常多,执行时间也可能会非常长,导致测试效率变得极低,甚至影响整个项目的进度。

但是,今天我要分享一个秘诀——使用pytest多进程/多线程执行测试用例,让你的测试速度提升数倍!这个方法不仅易于实现,而且效果显著,在我们团队中已经推广了很长时间。

接下来,我将向大家详细介绍这个方法的具体实现过程和注意事项,希望能帮助大家提高测试效率,更好地完成各自的测试任务。话不多说我们直接开始今天的学习好吧!

使用pytest多进程/多线程执行测试用例的原因

  • 实际项目中的用例数量会非常多,几百上千;如果采用单进程串行执行的话会非常耗费时间。假设每条用例耗时2s,1000条就需要2000s $\approx$ 33min;还要加上用例加载、测试前/后置套件等耗时;导致测试执行效率会相对低。
  • 想象一下如果开发改动一块代码,我们需要回归一下,这时候执行一下自动化用例需要花费大半个小时或者好几个小时的时间,这是我们无法容忍的。
  • 为了节省项目测试时间,需要多个测试用例同时并行执行;这就是一种分布式场景来缩短测试用例的执行时间,提高效率。

分布式执行用例的原则:

  • 用例之间是相互独立的,没有依赖关系,完全可以独立运行;
  • 用例执行没有顺序要求,随机顺序都能正常执行;
  • 每个用例都能重复运行,运行结果不会影响其他用例。

项目结构
测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!
测试脚本

# test1/test_1.py
import time

def test1_test1():
    time.sleep(1)
    assert 1 == 1, "1==1"


def test1_test2():
    time.sleep(1)
    assert 1 == 1, "1==1"
    
    
class TestDemo1:
    def test_inner_1(self):
        time.sleep(1)
        assert 1 == 1, "1==1"


class TestDemo2:
    def test_inner_2(self):
        time.sleep(1)
        assert 1 == 1, "1==1"
# test1/inner/test_3.py
import time

def test3_test1():
    time.sleep(1)
    assert 1 == 1, "1==1"


def test3_test2():
    time.sleep(1)
    assert 1 == 1, "1==1"
    
# test2/test_2.py
import time

def test2_test1():
    time.sleep(1)
    assert 1 == 1, "1==1"


def test2_test2():
    time.sleep(1)
    assert 1 == 1, "1==1"
    
# test2/inner/test_3.py
import time

def test4_test1():
    time.sleep(1)
    assert 1 == 1, "1==1"


def test4_test2():
    time.sleep(1)
    assert 1 == 1, "1==1"

正常执行:需要8.10s 测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

多进程执行用例之pytest-xdist

安装:

pip install pytest-xdist

多cpu并行执行用例,直接加个-n参数即可,后面num参数就是并行数量,比如num设置为3

pytest -v -n num
 

参数:

  1. -n auto : 自动侦测系统里的CPU数目
  2. -n num : 指定运行测试的处理器进程数

多进程并行执行:耗时2.66s大大的缩短了测试用例的执行时间。


测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

pytest-xdist分布式测试的原理:

  1. xdist的分布式类似于一主多从的结构,master负责下发命令,控制slave;slave根据master的命令执行特定测试任务。

  2. 在xdist中,主是master,从是workers;xdist会产生一个或多个workers,workers都通过master来控制,每个worker相当于一个mini版pytest执行器 。

  3. master不执行测试任务,只对worker收集到的所有用例进行分发;每个worker负责执行测试用例,然后将执行结果反馈给master;由master统计最终测试结果。

pytest-xdist分布式测试的流程:

第一步:master创建worker

  1. master在测试会话(test session)开始前产生一个或多个worker。

  2. master和worker之间是通过execnet网关来通信的。

  3. 实际编译执行测试代码的worker可能是本地机器也可能是远程机器。

第二步:workers收集测试项用例

  1. 每个worker类似一个迷你型的pytest执行器

  2. worker会执行一个完整的test collection过程。【收集所有测试用例的过程】

  3. 然后把测试用例的ids返回给master。【ids表示收集到的测试用例路径】

  4. master不执行任何测试用例。

注意:分布式测试(pytest-xdist)方式执行测试时不会输出测试用例中的print内容,因为master并不执行测试用例。

第三步:master检测workers收集到的测试用例集

  1. master接收到所有worker收集的测试用例集之后,master会进行一些完整性检查,以确保所有worker都收集到一样的测试用例集(包括顺序)。

  2. 如果检查通过,会将测试用例的ids列表转换成简单的索引列表,每个索引对应一个测试用例的在原来测试集中的位置。

  3. 这个方案可行的原因是:所有的节点都保存着相同的测试用例集。

  4. 并且使用这种方式可以节省带宽,因为master只需要告知workers需要执行的测试用例对应的索引,而不用告知完整的测试用例信息。

第四步:master分发测试用例

有以下四种分发策略:命令行参数 --dist=mode选项(默认load)

  • each:master将完整的测试索引列表分发到每个worker,即每个worker都会执行一遍所有的用例。
    测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

  • load:master将大约$\frac{1}{n}$的测试用例以轮询的方式分发到各个worker,剩余的测试用例则会等待worker执行完测试用例以后再分发;每个用例只会被其中一个worker执行一次。
    测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

  • loadfile:master分发用例的策略为按ids中的文件名(test_xx.py或xx_test.py)进行分发,即同一个测试文件中的测试用例只会分发给其中一个worker;具有一定的隔离性。
    测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

  • loadscope:master分发用例对策略为按作用域进行分发,同一个模块下的测试函数或某个测试类中的测试函数会分发给同一个worker来执行;即py文件中无测试类的话(只有测试function)将该模块分发给同一个worker执行,如果有测试类则会将该文件中的测试类只会分发给同一个worker执行,多个类可能分发给多个worker;目前无法自定义分组,按类 class 分组优先于按模块 module 分组。
    测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

注意:可以使用pytest_xdist_make_scheduler这个hook来实现自定义测试分发逻辑。
如:想按目录级别来分发测试用例:

from xdist.scheduler import LoadScopeScheduling


class CustomizeScheduler(LoadScopeScheduling):
	def _split_scope(self, nodeid):
		return nodeid.split("/", 1)[0]


def pytest_xdist_make_scheduler(config, log):
	return CustomizeScheduler(config, log)
  1. 只需在最外层conftest中继承xdist.scheduler.LoadScopeScheduling并重写_split_scope方法
  2. 重写钩子函数pytest_xdist_make_scheduler
pytest -v -n 4 --dist=loadfile
 

测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!

第五步:worker执行测试用例

  1. workers 重写了pytest_runtestloop:pytest的默认实现是循环执行所有在test_session这个对象里面收集到的测试用例。
  2. 但是在xdist里, workers实际上是等待master为其发送需要执行的测试用例。
  3. 当worker收到测试任务, 就顺序执行pytest_runtest_protocol
  4. 值得注意的一个细节是:workers 必须始终保持至少一个测试用例在的任务队列里, 以兼容pytest_runtest_protocol(item, nextitem)hook的参数要求,为了将nextitem传给hook。
  5. master在worker执行完分配的一组测试后,基于测试执行时长以及每个worker剩余测试用例综合决定是否向这个worker发送更多的测试用例。
  6. worker会在执行最后一个测试项前等待master的更多指令。
  7. 如果它收到了更多测试项, 那么就可以安全的执行 pytest_runtest_protocol,因为这时nextitem参数已经可以确定。
  8. 如果它收到一个 shutdown信号, 那么就将nextitem参数设为None, 然后执行 pytest_runtest_protocol

第六步:测试结束

  1. 当master没有更多执行测试任务时,它会发送一个shutdown信号给所有worker。
  2. 当worker将剩余测试用例执行完后退出进程。
  3. 当workers在测试执行结束时,会将结果被发送回master,然后master将结果转发到其他pytest hooks比如:pytest_runtest_logstartpytest_runtest_logreport 确保整个测试活动进行正常运作。
  4. master等待所有worker全部退出并关闭测试会话。

注意:pytest-xdist 是让每个 worker 进程执行属于自己的测试用例集下的所有测试用例。这意味着在不同进程中,不同的测试用例可能会调用同一个 scope 范围级别较高(例如session)的 fixture,该 fixture 则会被执行多次,这不符合 scope=session 的预期。

pytest-xdist 没有内置的支持来确保会话范围的 fixture 仅执行一次,但是可以通过使用文件锁进行进程间通信来实现;让scope=session 的 fixture 在 test session 中仅执行一次。

示例:需要安装filelock 包,安装命令pip install filelock

  1. 比如只需要执行一次login(或定义配置选项、初始化数据库连接等)。
  2. 当第一次请求这个fixture时,则会利用FileLock仅产生一次fixture数据。
  3. 当其他进程再次请求这个fixture时,则不会重复执行fixture。
import pytest
import uuid
from filelock import FileLock

 
@pytest.fixture(scope="session")
def login(tmp_path_factory, worker_id):
    # 代表是单机运行
    if worker_id == "master":
        token = uuid.uuid4()
        print("fixture:请求登录接口,获取token", token)
        os.environ['token'] = token
        
        return token
        
    # 分布式运行
    # 获取所有子节点共享的临时目录,无需修改【不可删除、修改】
    root_tmp_dir = tmp_path_factory.getbasetemp().parent
    fn = root_tmp_dir / "data.json"
    with FileLock(str(fn) + ".lock"):
        if fn.is_file():  # 代表已经有进程执行过该fixture
            token = json.loads(fn.read_text())
        else:  # 代表该fixture第一次被执行
            token = uuid.uuid4()
            fn.write_text(json.dumps(token))
        # 最好将后续需要保留的数据存在某个地方,比如这里是os的环境变量
        os.environ['token'] = token
	return token

多线程执行用例之pytest-parallel

用于并行并发测试的 pytest 插件

pip install pytest-parallel

常用参数配置

  1. --workers=n :多进程运行需要加此参数, n是进程数。默认为1

  2. --tests-per-worker=n :多线程需要添加此参数,n是线程数

如果两个参数都配置了,就是进程并行;每个进程最多n个线程,总线程数:进程数*线程数

【注意】

  1. 在windows上进程数永远为1。

  2. 需要使用 if name == “main” :在命令行窗口运行测试用例会报错

示例:

  • pytest test.py --workers 3 :3个进程运行
  • pytest test.py --tests-per-worker 4 :4个线程运行
  • pytest test.py --workers 2 --tests-per-worker 4 :2个进程并行,且每个进程最多4个线程运行,即总共最多8个线程运行。

    import pytest

    import pytest
    
    
    def test_01():
        print('测试用例1操作')
    
    def test_02():
        print('测试用例2操作')
    
    def test_03():
        print('测试用例3操作')
    
    def test_04():
        print('测试用例4操作')
        
    def test_05():
        print('测试用例5操作')
    
    def test_06():
        print('测试用例6操作')
        
    def test_07():
        print('测试用例7操作')
    
    def test_08():
        print('测试用例8操作')
    
    
    if __name__ == "__main__":
        pytest.main(["-s", "test_b.py", '--workers=2', '--tests-per-worker=4'])

pytest-parallel与pytest-xdist对比说明:

  • pytest-parallel 比 pytst-xdist 相对好用,功能支持多;
  • pytst-xdist 不支持多线程;
  • pytest-parallel 支持python3.6及以上版本,所以如果想做多进程并发在linux或者mac上做,在Windows上不起作用(Workers=1),如果做多线程linux/mac/windows平台都支持,进程数为workers的值。
  • pytest-xdist适用场景为:
    • 不是线程安全的
    • 多线程时性能不佳的测试
    • 需要状态隔离
  • pytest-parallel对于某些用例(如 Selenium)更好:
    • 可以是线程安全的
    • 可以对 http 请求使用非阻塞 IO 来提高性能

简而言之,pytest-xdist并行性pytest-parallel是并行性和并发性。

结语

这篇贴子到这里就结束了,最后,希望看这篇帖子的朋友能够有所收获。

 pytest教程获取方式:留言【pytest】即可

如果你觉得文章还不错,请大家 点赞、分享、留言 下,因为这将是我持续输出更多优质文章的最强动力!文章来源地址https://www.toymoban.com/news/detail-456535.html

到了这里,关于测试不够快?试试这招!让pytest多进程/多线程执行测试用例,轻松提升测试效率!的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • python pytest失败用例重新执行

    python pytest自动化测试时,失败用例重跑,可以采用pytest的库rerunsfailurs 安装步骤: 1. pip install pytest-rerunsfailures 2.如果需要html的测试报告,需要安装 pip instal pytest-html 三种方式: 1、在python自动化项目根目录下新建pytest.ini,在配置文件中写入以下内容: reruns为失败用例重跑的

    2024年02月11日
    浏览(36)
  • Pytest 框架执行用例流程浅谈

    根据以下简单的代码示例,我们将 从源码的角度分析其中的关键加载执行步骤,对pytest整体流程架构有个初步学习。 代码示例: 通过  pytest test_example.py 运行此代码示例后, 会触发pytest的入口函数main(),这个函数定义在src/pytest/__main__.py中,它的作用是创建一个PytestConfig对象

    2024年02月11日
    浏览(30)
  • pytest(一):基础功能(执行用例、allure报告、数据驱动)

    pytest是python语言中一款强大的单元测试框架,用来管理和组织测试用例,可应用在单元测试、自动化测试工作中。  官网:(https://docs.pytest.org/en/7.2.x/) 文章主要以unittest为参考分析pytest pytest主要作用是编写测试用例、收集用例、执行用例、生成测试结果文件(html、xml) unittest: 模

    2024年02月12日
    浏览(33)
  • 静图如何在线做动图?试试这招三秒生成

    如何将静态图片做成gif动图?不知道大家手上有没有一些好玩有趣的图片,想要将这些有趣的图片变成更有趣的动态gif图片应该如何操作呢?很简单,通过使用gif动画图片(https://www.gif.cn/)制作工具上传jpg、png格式图片,轻松一键就能快速完成图片合成gif图的操作,具体步骤

    2024年02月06日
    浏览(25)
  • 测试框架pytest教程(2)-用例依赖库-pytest-dependency

    对于 pytest 的用例依赖管理,可以使用  pytest-dependency  插件。该插件提供了更多的依赖管理功能,使你能够更灵活地定义和控制测试用例之间的依赖关系。 Using pytest-dependency — pytest-dependency 0.5.1 documentation 安装 pytest-dependency 插件: 依赖方法和被依赖方法都需要使用装饰器

    2024年02月11日
    浏览(25)
  • Pytest框架测试用例规则和运行方式

    目录 一、默认的测试用例规则 二、测试用例执行顺序 三、测试用例运行方式 3.1.主函数模式 3.1.1.主函数模式:4种运行方式  3.1.2.文件框架如下图  3.2.命令行模式 3.2.1.命令行模式:4种运行方式  3.2.2.第2种运行方式框架 3.3.通过读取配置文件pytest.ini运行 3.3.1.pytest.ini 文件注

    2024年02月11日
    浏览(42)
  • 软件测试|详解 Pytest 参数化:简化测试用例的编写

    简介 Pytest 是一个广泛使用的 Python 测试框架,它提供了丰富的功能来编写和执行测试用例。其中一个强大的特性是参数化,它允许我们通过一种简洁的方式运行多个输入参数的相似测试用例,从而减少冗余的代码。本文将详细介绍 Pytest 的参数化功能以及如何使用它来简化测

    2024年01月20日
    浏览(43)
  • 实战干货,pytest自动化测试-Git中的测试用例运行(详细)

    我们每天写完自动化用例后都会提交到 git 仓库,随着用例的增多,为了保证仓库代码的干净,当有用例新增的时候,我们希望只运行新增的未提交 git 仓库的用例。 pytest-picked 插件可以实现只运行未提交到git仓库的代码。 pytest-picked 使用命令行安装 可使用参数 使用示例:

    2024年02月09日
    浏览(46)
  • 自动化用例编写思路 (使用pytest编写一个测试脚本)

    目录 一,明确测试对象 二,编写测试用例 构造请求数据 封装测试代码 断言设置 三,执行脚本获取测试结果 四,总结 经过之前的学习铺垫,我们尝试着利用pytest框架编写一条接口自动化测试用例,来厘清接口自动化用例编写的思路。 我们在百度搜索天气查询,会出现如下

    2024年02月16日
    浏览(45)
  • Pytest实现用例失败截图并且在测试报告中可以查看

    Pytest+Selenium是UI自动化常用得框架,结合Allure可以给出优美得测试报告,失败的case可以查看错误日志,但是对于UI自动化来说,最直观的还是可以通过截图来查看失败原因,更方便测试人员定位问题。 钩子函数pytest_runtest_makereport pytest提供了pytest_runtest_makereport这个方法,可以

    2024年02月09日
    浏览(29)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包