本文主要是介绍pytest测试框架系列 - pytest-xdist 分布式、多进程并发执行用例你会吗?,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
## 前言
场景:随着项目越来越大、复杂,用例越来越多,串行的执行就需要太多的时间,就像测试部门一样,项目太多,项目完成的时间就越来越久,这就需要我们招聘更多的人,同时来测试项目,这样就提高了测试效率,但是需要尽量减少项目测试之间的关联性、耦合性。
Pytest 框架提供了一个`pytest-xdist` 插件帮我们做了这件事情,我们只需要简单的使用即可。
## **用例需要并发执行注意点**
- 每条用例是独立的,没有依赖关系,完全解耦,用例可以完全独立运行
- 用例执行没有顺序,随机顺序都能正常执行
- 每个用例都能重复运行,运行结果不会影响其他用例
## pytest-xdist 详解 (建议掌握程度:☆☆☆☆☆)
### 安装
- 在命令行窗口输入: `pip install pytest-xdist`
- 查看安装版本:`pip show pytest-xdist`
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710133836425.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
### 使用
使用方法 :
- pytest -n num (代表使用num个CPU)
- pytest -n auto
- n auto:可以自动检测到系统的CPU核数;从测试结果来看,检测到的是逻辑处理器的数量
- 使用auto等于利用了所有CPU来跑用例,此时CPU占用率会特别高
说明:建议最多使用1/2的CPU个数来进行执行,消耗资源太多,导致电脑太卡
**先看下不使用分布式执行**
```python
# !/usr/bin/python3
# _*_coding:utf-8 _*_
""""
# @Time :2021/7/10 13:31
# @Author : king
# @File :test_xdist.py
# @Software :PyCharm
# @blog :https://blog.csdn.net/u010454117
# @WeChat Official Account: 【测试之路笔记】
"""
import pytest
import time
def test_01():
time.sleep(1)
print("我是 test_01 用例")
assert True
def test_02():
time.sleep(1)
print("我是 test_02 用例")
assert True
def test_03():
time.sleep(1)
print("我是 test_03 用例")
assert True
def test_04():
time.sleep(1)
print("我是 test_04 用例")
assert True
def test_05():
time.sleep(1)
print("我是 test_05 用例")
assert True
def test_06():
time.sleep(1)
print("我是 test_06 用例")
assert True
def test_07():
time.sleep(1)
print("我是 test_07 用例")
assert True
def test_08():
time.sleep(1)
print("我是 test_08 用例")
assert True
def test_09():
time.sleep(1)
print("我是 test_09 用例")
assert True
def test_10():
time.sleep(1)
print("我是 test_10 用例")
assert True
def test_11():
time.sleep(1)
print("我是 test_11 用例")
assert True
def test_12():
time.sleep(1)
print("我是 test_12 用例")
assert True
if __name__ == '__main__':
pytest.main(["-s", "-v"])
```
执行结果:代码每个用例sleep了1秒,可以看出来串行需要12秒,如果是成千上万的用例,需要的时间就特别长了
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710143752943.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
**使用 pytest -n num**
示例还是上面示例,直接看执行结果:命令输入`pytest -n 3 test_xdist.py`, 看执行时间是不是从12.20秒到4.75秒,是不是减少了2倍
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710144520237.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
**使用 pytest -n auto**
示例还是上面示例,直接看执行结果:命令输入`pytest -n auto test_xdist.py`,启动了8个进程,代表执行电脑总共8个虚拟CPU,因为用例不多,加上启动进程需要时间,所以跟3个进行消耗时间差不多,如果用例越多效果越明显,建议使用1/2的电脑CPU运行即可
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710145041204.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
### 看看多个文件时执行情况
- `test_xdist.py` 和 `test_xdist_02.py` 和 `test_xdist_03.py` 里面代码 都是一样
- 使用`pytest -v -n 3 test_xdist.py test_xdist_02.py test_xdist_03.py` 执行
执行结果:看结果是,先收集了所有用例,创建了3个执行器,分别执行对应的用例,3个执行器都是从第一个文件往后依次执行
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710150312832.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
## **问题:如果按照作用域分配给worker用例分别执行该怎么做**
如果我们想要按照用例的作用域进行执行,该怎么处理呢?3个执行器只能分别执行一个模块(一个py文件)或者同一个文件里面同一个类只给一个执行器执行。
通过`pytest-xdist`的源码发现有这一段参数配置说明:
```python
group.addoption(
"--dist",
metavar="distmode",
action="store",
choices=["each", "load", "loadscope", "loadfile", "no"],
dest="dist",
default="no",
help=(
"set mode for distributing tests to exec environments.\n\n"
"each: send each test to all available environments.\n\n"
"load: load balance by sending any pending test to any"
" available environment.\n\n"
"loadscope: load balance by sending pending groups of tests in"
" the same scope to any available environment.\n\n"
"loadfile: load balance by sending test grouped by file"
" to any available environment.\n\n"
"(default) no: run tests inprocess, don't distribute."
),
```
**说明:**
- `--dist=loadscope` 将按照同一个作用域方法来分组,然后将每个测试组发给可以执行的worker,确保同一个组的测试用例在同一个进程中执行
- `--dist=loadfile` 按照同一个文件名来分组,然后将每个测试组发给可以执行的worker,确保同一个组的测试用例在同一个进程中执行
- `--dist=each` 是将每个用例,分别发给所有的执行器worker,相当于开了几个执行器worker,同一个用例就执行几遍
- `--dist=load` 将待运行的用例随机发给可用的执行器worker,用例执行顺序随机的,目前默认采用这种方式
### `--dist=loadfile` 示例:
示例代码还是上述代码,执行命令:`pytest -v -n 3 --dist=loadfile test_xdist.py test_xdist_02.py test_xdist_03.py`
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710153935297.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
结果:从结果可以看下 `gw0` 执行 `test_xdist.py` 模块, `gw1` 执行 `test_xdist_02.py` 模块, `gw2` 执行 `test_xdist_03.py` 模块
### `--dist=loadscope` 示例:
`test_xdist.py` 示例代码:
```python
# !/usr/bin/python3
# _*_coding:utf-8 _*_
""""
# @Time :2021/7/10 13:31
# @Author : king
# @File :test_xdist.py
# @Software :PyCharm
# @blog :https://blog.csdn.net/u010454117
# @WeChat Official Account: 【测试之路笔记】
"""
import pytest
import time
class TestDist01:
def test_01(self):
time.sleep(1)
print("我是 test_01 用例")
assert True
def test_02(self):
time.sleep(1)
print("我是 test_02 用例")
assert True
def test_03(self):
time.sleep(1)
print("我是 test_03 用例")
assert True
class TestDist02:
def test_04(self):
time.sleep(1)
print("我是 test_04 用例")
assert True
def test_05(self):
time.sleep(1)
print("我是 test_05 用例")
assert True
def test_06(self):
time.sleep(1)
print("我是 test_06 用例")
assert True
class TestDist03:
def test_07(self):
time.sleep(1)
print("我是 test_07 用例")
assert True
def test_08(self):
time.sleep(1)
print("我是 test_08 用例")
assert True
def test_09(self):
time.sleep(1)
print("我是 test_09 用例")
assert True
class TestDist04:
def test_10(self):
time.sleep(1)
print("我是 test_10 用例")
assert True
def test_11(self):
time.sleep(1)
print("我是 test_11 用例")
assert True
def test_12(self):
time.sleep(1)
print("我是 test_12 用例")
assert True
if __name__ == '__main__':
pytest.main()
```
**执行结果**
执行命令:`pytest -v -n 3 --dist=loadscope test_xdist.py`
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710155037532.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
结果:从结果可以看下 `gw0` 执行 `test_xdist.py` 模块的 `TestDist01` 和 `TestDist04` 类, `gw1` 执行 `test_xdist.py` 模块的`TestDist01` 类, `gw2` 执行 `test_xdist.py` 模块的 `TestDist03`
### `--dist=each` 示例:
与上述 `test_xdist.py` 示例代码一样,执行命令: `pytest -v -n 3 --dist=each test_xdist.py`
![在这里插入图片描述](https://www.www.zyiz.net/i/ll/?i=20210710155735454.png?,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3UwMTA0NTQxMTc=,size_16,color_FFFFFF,t_70)
结果:从上面结果可以看出来,每天用例被执行了3遍
### `--dist=load` 和 `--dist==no` 示例:
- 略,前面最开始执行示例,随机将待执行的用例分别给可用的执行器worker执行
## 总结
- 使用并行测试 加上` -n num` 或者 `-n auto` 参数即可使用
- 可以根据参数 `--dist=loadfile`、 `--dist=loadscope`、`--dist=each`、`--dist=load` 和 `--dist==no`设置不同的执行器worker执行模式
- 如果存在每条用例重复执行多次的场景,采用`--dist=each`模式,开几个执行器worker就执行几次
以上为内容纯属个人理解,如有不足,欢迎各位大神指正,转载请注明出处!
>**如果觉得文章不错,欢迎关注微信公众号,微信公众号每天推送相关测试技术文章**
个人微信号:搜索 【测试之路笔记】
这篇关于pytest测试框架系列 - pytest-xdist 分布式、多进程并发执行用例你会吗?的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!