返回顶部
首页 > 资讯 > 后端开发 > Python >pytest多进程或多线程执行测试实例
  • 493
分享到

pytest多进程或多线程执行测试实例

2024-04-02 19:04:59 493人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录前言:分布式执行用例的原则:项目结构测试脚本多进程执行用例之pytest-xdistpytest-xdist分布式测试的原理:pytest-xdist分布式测试的流程:第一步:m

前言:

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

分布式执行用例的原则:

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

项目结构

测试脚本

# 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-xdist

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

pytest -v -n num

参数:

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

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

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

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

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

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

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

第一步:master创建worker

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

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

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

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

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

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

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

  • master不执行任何测试用例。

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

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

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

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

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

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

第四步:master分发测试用例

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

each:master将完整的测试索引列表分发到每个worker,即每个worker都会执行一遍所有的用例。

load:master将大约$\frac{1}{n}$的测试用例以轮询的方式分发到各个worker,剩余的测试用例则会等待worker执行完测试用例以后再分发;每个用例只会被其中一个worker执行一次。

loadfile:master分发用例的策略为按ids中的文件名(test_xx.py/xx_test.py)进行分发,即同一个测试文件中的测试用例只会分发给其中一个worker;具有一定的隔离性。

loadscope:master分发用例对策略为按作用域进行分发,同一个模块下的测试函数或某个测试类中的测试函数会分发给同一个worker来执行;即py文件中无测试类的话(只有测试function)将该模块分发给同一个worker执行,如果有测试类则会将该文件中的测试类只会分发给同一个worker执行,多个类可能分发给多个worker;目前无法自定义分组,按类 class 分组优先于按模块 module 分组。

注意:可以使用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)
  • 只需在最外层conftest中继承xdist.scheduler.LoadScopeScheduling并重写_split_scope方法
  • 重写钩子函数pytest_xdist_make_scheduler
pytest -v -n 4 --dist=loadfile

第五步:worker执行测试用例

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

第六步:测试结束

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

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

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

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

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

 
@pytest.fixture(scope="session")
def login(tmp_path_factory, worker_id):
    # 代表是单机运行
    if worker_id == "master":
        token = str(random())
        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 = str(random())
            fn.write_text(json.dumps(token))
        # 最好将后续需要保留的数据存在某个地方,比如这里是os的环境变量
        os.environ['token'] = token
	return token

线程执行用例之pytest-parallel

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

pip install pytest-parallel

常用参数配置

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

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

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

【注意】

  • windows上进程数永远为1。

  • 需要使用 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


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多进程或多线程执行测试的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: pytest多进程或多线程执行测试实例

本文链接: https://lsjlt.com/news/119085.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • pytest多进程或多线程执行测试实例
    目录前言:分布式执行用例的原则:项目结构测试脚本多进程执行用例之pytest-xdistpytest-xdist分布式测试的原理:pytest-xdist分布式测试的流程:第一步:m...
    99+
    2024-04-02
  • python 多线程与多进程效率测试
    目录1、概述2、代码练习3、运行结果1、概述 在Python中,计算密集型任务适用于多进程,IO密集型任务适用于多线程 正常来讲,多线程要比多进程效率更高,因为进程间的切换需要的资...
    99+
    2024-04-02
  • pytest实现多进程与多线程运行超好用的插件
    目录前言一、pytest-parallel二、pytest-xdist三、对比说明四、特别注意前言 如果想分布式执行用例,用例设计必须遵循以下原则: 1、用例之间都是独立的,2、用例...
    99+
    2024-04-02
  • 怎么进行Python多线程并发的简单测试
    怎么进行Python多线程并发的简单测试,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。之前也写了一些简单的Python程序,对于多线程的并发一直没有涉及,今天决定先突破一下...
    99+
    2023-06-04
  • Java多线程并发、并行、线程与进程实例分析
    本篇内容介绍了“Java多线程并发、并行、线程与进程实例分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、并发与并行并发:指两个或多个事...
    99+
    2023-07-02
  • Node.js中的多进程和多线程实例分析
    本篇内容主要讲解“Node.js中的多进程和多线程实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Node.js中的多进程和多线程实例分析”吧!我们都知道...
    99+
    2024-04-02
  • python 并发执行之多线程
        正常情况下,我们在启动一个程序的时候。这个程序会先启动一个进程,启动之后这个进程会拉起来一个线程。这个线程再去处理事务。也就是说真正干活的是线程,进程这玩意只负责向系统要内存,要资源但是进程自己是不干活的。默认情况下只有一个进程只会...
    99+
    2023-01-31
    之多 线程 python
  • 【目标检测】YOLOv5多进程/多线程推理加速实验
    前言 最近在研究如何让YOLOv5推理得更快,总体看来,主要有以下这些思路: 使用更快的 GPU,即:P100 -> V100 -> A100多卡GPU推理减小模型尺寸,即YOLOv5x -> YOL...
    99+
    2023-09-07
    目标检测 python 人工智能
  • python程序默认执行与多线程
    1程序执行流程有类似脚本程序或编程经验的同学都知道,程序默认是自上而下,从左到右的按顺序执行,也叫串行执行;而多线程类似于并行执行,即A模块(函数)执行时B也执行不需要等A执行完再执行,这里请区别对待并发执行(同一时间执行);以上是简单概...
    99+
    2023-01-31
    多线程 程序 python
  • Java多线程并发与并行和线程与进程案例
    目录一、并发与并行二、线程与进程三、创建线程类前言: 程序在没有跳转语句的前提下,都是由上至下依次执行,那现在想要设计一个程序,边打游戏边听歌,怎么设计? 要解决上述问题,咱们得使用...
    99+
    2024-04-02
  • java多线程并发执行怎么实现
    在Java中实现多线程的并发执行有多种方式,以下是其中的几种常见方法:1. 继承Thread类:创建一个继承自Thread类的子类,...
    99+
    2023-09-27
    java
  • laravel多线程执行队列怎么实现
    在Laravel中,可以使用`illuminate/queue`组件来实现多线程执行队列的功能。首先,需要在项目中安装`illumi...
    99+
    2023-09-06
    laravel
  • java怎么实现多线程并发执行
    Java实现多线程并发执行的方式有两种:继承Thread类和实现Runnable接口。 继承Thread类: 定义一个类,继承...
    99+
    2023-10-25
    java
  • python并发执行之多进程
        多进程顾名思义程序启动的时候运行多个进程,每个进程启动一条线程进行程序处理。 没启动一个进程就要单独划分一块内存资源。就像工厂的厂房。为了提高效率每多添加一条生产线就要单独再盖一个厂房。每个厂房相互是独立的。所以启动多进程是很消耗资...
    99+
    2023-01-31
    之多 进程 python
  • Java多线程面试题实例分析
    这篇文章主要介绍了Java多线程面试题实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java多线程面试题实例分析文章都会有所收获,下面我们一起来看看吧。问题一A线程正在执行一个对象中的同步方法,B线程是...
    99+
    2023-06-29
  • Java 多线程 之 银行ATM实例
    转载于 : http://www.verejava.com/id=16992914422268 package com.thread;import java.util.Scanner;public&n...
    99+
    2023-06-02
  • python多线程方式执行多个bat代码
    python多线程方式执行多个bat的代码,感兴趣的朋友可以参考下。 import threading from win32api import * class MyThread(threading...
    99+
    2022-06-04
    多个 多线程 代码
  • 如何进行php多线程编程?
    在现代计算机领域中,多线程并发编程已经成为一种非常常见的编程方式。而在PHP语言中,多线程编程同样也是非常重要的一种技能。本文将向您介绍如何进行PHP多线程编程。什么是多线程编程?多线程编程是指在同一个程序中同时执行多个线程的编程方式。在多...
    99+
    2023-05-22
    编程 PHP 多线程
  • 如何进行C++多线程编程?
    如何进行C++多线程编程随着计算机硬件的不断发展,多核处理器已经成为现代计算机的主流。为了充分利用多核处理器的性能,多线程编程成了一个重要的技能。C++是一门强大的编程语言,也提供了很多多线程编程的工具和库。本文将介绍如何进行C++多线程编...
    99+
    2023-11-04
    编程 多线程编程 C++ 多线程
  • Golang多进程编程指南:实现并发执行
    在当今快节奏的互联网时代,高效的并发编程成为了开发者们不可或缺的技能之一。而在众多编程语言中,Golang(或称Go语言)以其优雅简洁的语法以及强大的并发支持而备受青睐。本文将从Gol...
    99+
    2024-02-29
    golang 并发 多进程 go语言
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作