小门板儿

Menu

pytest多进程与多线程

当一些项目如果用例比较多,执行一次自动化测试,耗时比较长;用例之间是独立的,没有依赖关系,完全可以独立运行;并且用例执行没有顺序要求,随机顺序都能正常执行;每个用例都能重复运行,运行结果不会影响其他用例时,此时可以选择采用分布式执行用例

一、pytest-xdist多进程

pytest-xdist 只支持多进程执行测试用例,不支持多线程执行

1、安装

pip install pytest-xdist

2、参数说明

参数说明:

  1. -n= 指定进程数,如 -n=4 表示开启4个cpu进行执行测试用例。
  2. pytest-xdist支持windows系统使用,同样也支持mac、linux。
  3. -n auto : 自动侦测系统里的CPU数目
if __name__ == '__main__':
    pytest.main(['-s', 'testcase/test_case.py', '-n=4'])

3、使用

test_a.py测试文件

import time
​
import pytest
def test_1_01():
    print("----------------->>> test_a_01")
    time.sleep(1)
    assert 1
    
def test_a_02():
    print("----------------->>> test_a_02")
    time.sleep(1)
    assert 1
​
def test_a_03():
    print("----------------->>> test_a_03")
    time.sleep(1)
    assert 1
​
def test_a_04():
    print("----------------->>> test_a_04")
    time.sleep(1)
    assert 1
    
if __name__ == '__main__':
    pytest.main(["-s", "test_a.py"])

test_b.py测试文件

import pytest
import time
​
def test_b_01():
    print("----------------->>> test_b_01")
    time.sleep(1)
    assert 1
​
def test_b_02():
    print("----------------->>> test_b_02")
    time.sleep(1)
    assert 1
​
def test_b_03():
    print("----------------->>> test_b_03")
    time.sleep(1)
    assert 1
​
def test_b_04():
    print("----------------->>> test_b_04")
    time.sleep(1)
    assert
​
if __name__ == '__main__':
    pytest.main(["-s", "test_b.py"])

正常运行以上代码,耗时:8.12s

设置运行数量为4,耗时:3.14s

4、pytest-xdist分布式测试的原理

前言

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

2、在xdist中,主是master,从是workers。

大致原理

1、xdist会产生一个或多个workers,workers都通过master来控制。

2、每个worker负责执行完整的测试用例集,然后按照master的要求运行测试,而master机不执行测试任务。

5、pytest-xdist分布式测试的流程

第一步:创建worker

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

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

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

第二步:收集测试项用例

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

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

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

4、master是不会执行任何测试用例集的。 注意:分布式测试(pytest-xdist)方式执行测试时不会输出测试用例中的print内容,因为主机并不执行测试用例,pycharm相当于一个master。

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

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

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

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

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

第四步:测试用例分发

--dist-mode选项

each:master将完整的测试索引列表分发到每个worker。

load:master将大约25%的测试用例以轮询的方式分发到各个worker,剩余的测试用例则会等待workers执行完测试用例以后再分发

注意:可以使用pytest_xdist_make_scheduler 这个hook来实现自定义测试分发逻辑。

第五步:测试用例的执行

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、worker会在执行最后一个测试项前等待master的更多指令。

6、如果它收到了更多测试项, 那么就可以安全的执行 pytest_runtest_protocol ,因为这时nextitem参数已经可以确定。

7、如果它收到一个 "shutdown"信号, 那么就将 nextitem 参数设为 None, 然后执行 pytest_runtest_protocol

第六步:测试用例再分发(--dist-mode=load)

1、当workers开始/结束执行时,会把测试结果返回给master,这样其他pytest hook比如: pytest_runtest_protocol就可以正常执行

2、master在worker执行完一个测试后,基于测试执行时长以及每个work剩余测试用例综合决定是否向这个worker发送更多的测试用例

第七步:测试结束

1、当master没有更多执行测试任务时,它会发送一个“shutdown”信号给所有worker。

2、当worker将剩余测试用例执行完后退出进程。

3、master等待所有worker全部退出。

4、然而此时仍需要处理诸如 pytest_runtest_logreport 等事件。

二、多线程运行测试用例(pytest-parallel)

1、安装

pip install pytest-parallel

2、常用参数配置

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

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

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

【注意】

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

②pytest-parallel加了多线程处理后,最后执行时间是运行时间最长的线程的时间。

示例:

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个线程运行。

windows下设置线程数为4,运行结果

三、pytest-parallel与pytest-xdist对比说明

1、 pytest-parallelpytst-xdist 相对好用,功能支持多。

2、 pytst-xdist 不支持多线程;

3、pytest-parallel 支持python3.6及以上版本,所以如果想做多进程并发在linux或者mac上做,在Windows上不起作用(Workers=1),如果做多线程linux/mac/windows平台都支持,进程数为workers的值。

参考文献:https://www.cnblogs.com/guanqibuyu/p/16549822.html

— 于 共写了3756个字
— 标签:

1,814条回应:“pytest多进程与多线程”

  1. tang说道:

    非常nice

  2. quanlin说道:

    棒棒哒

  3. F说道:

    print(“三个六”)