Pytest系列(30)- 使用 pytest-xdist 分布式插件,如何保证 scope=session 的 fixture 在多进程运行情况下仍然能只运行一次
如果你还想从头学起Pytest,可以看看这个系列的文章哦!
https://www.cnblogs.com/poloyy/category/1690628.html
背景
- 使用 pytest-xdist 分布式插件可以加快运行,充分利用机器多核 CPU 的优势
- 将常用功能放到 fixture,可以提高复用性和维护性
- 做接口自动化测试的时候,通常我们会将登录接口放到 fixture 里面,并且 scope 会设置为 session,让他全局只运行一次
- 但是当使用 pytest-xdist 的时候,scope=session 的 fixture 无法保证只运行一次,官方也通报了这一问题
官方描述
- pytest-xdist 的设计使每个工作进程将执行自己的测试集合并执行所有测试子集,这意味着在不同的测试过程中,要求高级范围的 fixture(如:session)将会被多次执行,这超出了预期,在某些情况下可能是不希望的
- 尽管 pytest-xdist 没有内置支持来确保 scope=session 的fixture 仅执行一次,但是可以通过使用锁定文件进行进程间通信来实现
前置知识
pytest-xdist 分布式插件使用详细教程可看
https://www.cnblogs.com/poloyy/p/12694861.html
分布式插件原理可看
https://www.cnblogs.com/poloyy/p/12703290.html
fixture 的使用详细教程
https://www.cnblogs.com/poloyy/p/12642602.html
官方文档
https://pypi.org/project/pytest-xdist/
官方解决办法(直接套用就行)
import json import pytest
from filelock import FileLock @pytest.fixture(scope="session")
def session_data(tmp_path_factory, worker_id):
if worker_id == "master":
# not executing in with multiple workers, just produce the data and let
# pytest's fixture caching do its job
return produce_expensive_data() # get the temp directory shared by all workers
root_tmp_dir = tmp_path_factory.getbasetemp().parent fn = root_tmp_dir / "data.json"
with FileLock(str(fn) + ".lock"):
if fn.is_file():
data = json.loads(fn.read_text())
else:
data = produce_expensive_data()
fn.write_text(json.dumps(data))
return data
- 若某个 scope = session 的 fixture 需要确保只运行一次的话,可以用上面的方法,直接套用,然后改需要改的部分即可(这个后面详细讲解)
- 官方原话:这项技术可能并非在每种情况下都适用,但对于许多情况下,它应该是一个起点,在这种情况下,对于 scope = session 的fixture 只执行一次很重要
后续栗子的代码
项目结构
xdist+fixture(文件夹)
│ tmp(存放 allure 数据文件夹)
│ conftest.py
│ test_1.py
│ test_2.py
│ test_3.py
│ __init__.py │
test_1.py 代码
import os def test_1(test):
print("os 环境变量",os.environ['token'])
print("test1 测试用例", test)
test_2.py 代码
import os def test_2(test):
print("os 环境变量",os.environ['token'])
print("test2 测试用例", test)
test_3.py 代码
import os def test_3(test):
print("os 环境变量",os.environ['token'])
print("test3 测试用例", test)
未解决情况下的栗子
conftest.py 代码
import os
import pytest
from random import random @pytest.fixture(scope="session")
def test():
token = str(random())
print("fixture:请求登录接口,获取token", token)
os.environ['token'] = token
return token
运行命令
pytest -n 3 --alluredir=tmp
运行结果



scope=session 的 fixture 很明显执行了三次,三个进程下的三个测试用例得到的数据不一样,明显不会是我们想要的结果
使用官方解决方法的栗子
#!/usr/bin/env python
# -*- coding: utf-8 -*- """
__title__ =
__Time__ = 2021/4/27 11:28
__Author__ = 小菠萝测试笔记
__Blog__ = https://www.cnblogs.com/poloyy/
"""
import json
import os
import pytest
from random import random
from filelock import FileLock @pytest.fixture(scope="session")
def test2(tmp_path_factory, worker_id):
token = str(random())
print("fixture:请求登录接口,获取token", token)
os.environ['token'] = token
return token @pytest.fixture(scope="session")
def test(tmp_path_factory, worker_id):
# 如果是单机运行 则运行这里的代码块【不可删除、修改】
if worker_id == "master":
"""
【自定义代码块】
这里就写你要本身应该要做的操作,比如:登录请求、新增数据、清空数据库历史数据等等
"""
token = str(random())
print("fixture:请求登录接口,获取token", token)
os.environ['token'] = 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():
# 读取数据,像登录操作的话就是 token 【不可删除、修改】
token = json.loads(fn.read_text())
os.environ['token'] = token
else:
"""
【自定义代码块】
跟上面 if 下面的代码块一样就行
"""
token = str(random())
print("fixture:请求登录接口,获取token", token)
os.environ['token'] = token
# 【不可删除、修改】
fn.write_text(json.dumps(token))
return token
运行命令
pytest -n 3 --alluredir=tmp
运行结果



可以看到 fixture 只执行了一次,不同进程下的测试用例共享一个数据 token
重点
- 读取缓存文件并不是每个测试用例都会读,它是按照进程来读取的
- 比如 -n 3 指定三个进程运行,那么有一个进程会执行一次 fixture(随机),另外两个进程会各读一次缓存
- 假设每个进程有很多个用例,那也只是读一次缓存文件,而不会读多次缓存文件
- 所以最好要将从缓存文件读出来的数据保存在特定的地方,比如上面代码的 os.environ 可以将数据保存在环境变量中
两个进程跑三个测试用例文件
还是上面栗子的代码
运行命令
pytest -n 2 --alluredir=tmp
运行结果



可以看到 test_3 的测试用例就没有读缓存文件了,每个进程只会读一次缓存文件,记住哦!
Pytest系列(30)- 使用 pytest-xdist 分布式插件,如何保证 scope=session 的 fixture 在多进程运行情况下仍然能只运行一次的更多相关文章
- Pytest系列(17)- pytest-xdist分布式测试的原理和流程
pytest-xdist分布式测试的原理 前言 xdist的分布式类似于一主多从的结构,master机负责下发命令,控制slave机:slave机根据master机的命令执行特定测试任务 在xdist ...
- Pytest系列(15)- 多重校验插件之pytest-assume的详细使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest中可以用pyth ...
- Pytest系列(16)- 分布式测试插件之pytest-xdist的详细使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 平常我们功能测试用例非常多时 ...
- Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 平常在做功能测试的时候,经常 ...
- Pytest系列(18)- 超美测试报告插件之allure-pytest的基础使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 官方介绍 Allure Frame ...
- Pytest系列(1) - 快速入门和基础讲解
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 目前有两种纯测试的测试框架, ...
- Pytest系列(14)- 配置文件pytest.ini的详细使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest配置文件可以改变 ...
- Pytest系列(十三)- 重复执行之pytest-repeat的使用
写在前面 这个插件,可以帮助我们很好的解决自动化测试过程中的一些偶线性bug难以复现的问题,但前提是,当前自动化脚本是独立的,不依赖任何其他脚本.个人觉得还是失败重运行的一种体现,就和TestNG是一 ...
- Pytest(15)pytest分布式执行用例
前言 平常我们功能测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟,如果单个测试人员执行需要1000分钟才能跑完 当项目非常紧急时,会需要协调多个测试资源来把任务分成两部分,于是执行时间 ...
随机推荐
- Django Admin 图片路径设置显示为图片(imageField显示方法设置)
一 使用环境 开发系统: windows IDE: pycharm 数据库: msyql,navicat 编程语言: python3.7 (Windows x86-64 executable in ...
- CCF(公共钥匙盒):思维+模拟
公共钥匙盒 201709-2 这题的思路一开始不是很清晰,一开始想用贪心去做.但是发现按照题目的思路不对.所以这里采用的是类似于多项式的加减的处理. #include<iostream> ...
- 学员和教师管理优化用例点整理v2.0
更新记录: 更新内容 更新人 更新时间 新建 Young 2021.01.08 12:06 彭洋洋确认结果疑问 Young 2021.01.08 15:06 问题集锦 1. 购买成功页点击完成返回路径 ...
- [THUPC2019] 找树
一.题目 点此看题 二.解法 这道题很离谱啊,看上去是求一个最大值,其实是把生成树权值为 \(i\) 的个数都给算出来,因为权值很小. 既然是生成树可以考虑矩阵树定理,我们考虑他是求这样一个式子: \ ...
- Eric Python IDE 论文数据图片生成
Python编写,基于跨平台的Qt GUI工具包,集成了高度灵活的Scintilla编辑器控件. 大括号匹配,错误突出显示和可配置语法突出显示. 拼写检查库的集成 内置Python调试器,包括支持调试 ...
- Hibernate学习实例
一 Hibernate简介 Hibernate是一种Java语言下的对象关系映射(ORM)解决方案.为面向对象的领域模型到传统的关系型数据库的映射提供了一个使用方便的框架. 二 Hibernate设计 ...
- Nodejs学习笔记(5) 文件上传系统实例
目录 2018.8.4更新: MySQL可以存放几乎任何类型的数据(图片.文档.压缩包等),但这不是最好的解决方案,正常情况下都是在数据库中存放文件路径,图片.音乐.视频.压缩包.文档等文件存放在硬 ...
- vim宏录制的操作
1:在vim编辑器normal模式下输入qa(其中a为vim的寄存器) 2:此时在按i进入插入模式,vim编辑器下方则会出现正在录制字样,此时便可以开始操作. 3:需要录制的操作完成后,在normal ...
- PTA 中序输出叶子结点
6-8 中序输出叶子结点 (10 分) 本题要求实现一个函数,按照中序遍历的顺序输出给定二叉树的叶结点. 函数接口定义: void InorderPrintLeaves( BiTree T); T ...
- 攻防世界 reverse evil
这是2017 ddctf的一道逆向题, 挑战:<恶意软件分析> 赛题背景: 员工小A收到了一封邮件,带一个文档附件,小A随手打开了附件.随后IT部门发现小A的电脑发出了异常网络访问请求,进 ...