如果你还想从头学起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 在多进程运行情况下仍然能只运行一次的更多相关文章

  1. Pytest系列(17)- pytest-xdist分布式测试的原理和流程

    pytest-xdist分布式测试的原理 前言 xdist的分布式类似于一主多从的结构,master机负责下发命令,控制slave机:slave机根据master机的命令执行特定测试任务 在xdist ...

  2. Pytest系列(15)- 多重校验插件之pytest-assume的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest中可以用pyth ...

  3. Pytest系列(16)- 分布式测试插件之pytest-xdist的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 平常我们功能测试用例非常多时 ...

  4. Pytest系列(13)- 重复执行用例插件之pytest-repeat的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 平常在做功能测试的时候,经常 ...

  5. Pytest系列(18)- 超美测试报告插件之allure-pytest的基础使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 官方介绍 Allure Frame ...

  6. Pytest系列(1) - 快速入门和基础讲解

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 目前有两种纯测试的测试框架, ...

  7. Pytest系列(14)- 配置文件pytest.ini的详细使用

    如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 前言 pytest配置文件可以改变 ...

  8. Pytest系列(十三)- 重复执行之pytest-repeat的使用

    写在前面 这个插件,可以帮助我们很好的解决自动化测试过程中的一些偶线性bug难以复现的问题,但前提是,当前自动化脚本是独立的,不依赖任何其他脚本.个人觉得还是失败重运行的一种体现,就和TestNG是一 ...

  9. Pytest(15)pytest分布式执行用例

    前言 平常我们功能测试用例非常多时,比如有1千条用例,假设每个用例执行需要1分钟,如果单个测试人员执行需要1000分钟才能跑完 当项目非常紧急时,会需要协调多个测试资源来把任务分成两部分,于是执行时间 ...

随机推荐

  1. 配置mysql数据库时出再错误:LookupError: No installed app with label 'admin'.

    版本: windows10+py37+django2.2 错误: 项目启动时出现,No installed app with label 'admin' 解决办法: 安装最新的 pip install ...

  2. Svelte 极简入门

    ​弹指之间即可完成.   注意:原文发表于 2017-8-7,随着框架不断演进,部分内容可能已不适用.     Svelte 是一种新型框架.   以往我们要引入一个框架或者类库,可以通过在页面上放置 ...

  3. Android实现三角形气泡效果方式汇总

    在开发过程中,我们可能会经常遇到这样的需求样式: 这张图是截取京东消息通知的弹出框,我们可以看到右上方有个三角形的气泡效果,这只是其中一种,三角形的方向还可以是上.下.左.右. 通过截图可以发现,气泡 ...

  4. SVN同步方式举例 ​​​​ FreeBSD

    FreeBSD base  默认安装了svnlite 不需要单独安装SVN 软件 svnlite co svn.freebsd.org/ports/head/ /usr/local/ports -r5 ...

  5. 单链表及基本操作(C语言)

    #include <stdio.h> #include <stdlib.h> /** * 含头节点单链表定义及基本操作 */ //基本操作函数用到的状态码 #define TR ...

  6. golang 三维向量相关操作

    package vector import ( "math" "fmt" )// 三维向量:(x,y,z) type Vector3 struct { X fl ...

  7. MySQL深入研究--学习总结(5)

    前言 接上文,继续学习后续章节.细心的同学已经发现,我整理的并不一定是作者讲的内容,更多是结合自己的理解,加以阐述,所以建议结合原文一起理解. 第20章<幻读是什么,幻读有什么问题?> 先 ...

  8. elf.h

    1 /* This file defines standard ELF types, structures, and macros. 2 Copyright (C) 1995-2019 Free So ...

  9. 汇编 JCC指令表

    JCC指令 中文含义 英文原意 检查符号位 典型c应用 JZ/JE 若为0则跳转:若相等则跳转 jump if zero;jump if equal ZF=1 if (i == j);if (i == ...

  10. springBoot高级:自动配置分析,事件监听,启动流程分析,监控,部署

    知识点梳理 课堂讲义 02-SpringBoot自动配置-@Conditional使用 Condition是Spring4.0后引入的条件化配置接口,通过实现Condition接口可以完成有条件的加载 ...