Appium 并发多进程基于 Pytest框架详解

news2024/12/23 19:40:17

目录

前言:

改造思路:

实现:

最后:

总结:

前言:

之前通过重写unittest的初始化方法加入设备参数进行并发,实现了基于unittest的appium多设备并发,但是考虑到unittest的框架实在过于简陋,也不方便后期的Jenkins的持续集成,所以想换一个框架来使用。

那么通过调研,pyhon+pytest+allure 这套框架很不错,pytest是一个单元测试框架,他可以集成很多插件,包括出错重试,参数化,等。在此特别是基于他的allure插件,能够和Jenkins完美兼容,生成美观强大的测试报告。

 

改造思路:

pytest框架和unittest框架明显不同,通过命令行启动,读取响应目录下的test开头的文件,进行执行用例。

而unittest却是通过将用例加载到TestSuite中,运行随测试集来执行用例

所以这边多进程就要换一种思路进行了。

基于pytest的结构和运行方式,那么思路如下:

运行方式:

1. pytest目录下会先加载conftest.py运行。

2. 该目录下加载test开头的py文件

3. 加载文件中Test开头的类

4. 加载Test类下test开头的方法

5. 通过命令行pytest.main([1, 2 ,3])带入1 2 3参数进行运行

解决思路:

1. 通过命令行把不同设备的参数传递给conftest.py

2. conftest中,使用传递过来的设备参数,连接设备到appium,并生成driver对象

3. 在各自的测试类和测试方法中,调用driver对象,进行测试操作

4. 生成allure测试报告

实现:

1. 通过命令行传递参数:

run中的设备池:

def devices_Pool():
    devices_list = []
    for i in range(0, len(getDevices())):
        _initApp = {}
        _initCaps = {}
        _initApp["devices"] = getDevices()[i]
        _initCaps["deviceName"] = getDevices()[i]
        _initCaps["platformVersion"] = getPhoneInfo(devices=_initCaps["deviceName"])["release"]
        _initCaps["platformName"] = "Android"
        _initApp["port"] = str(random.randint(4700, 4900))
        _initApp["bport"] = str(random.randint(4700, 4900))
        _initApp["systemPort"] = str(random.randint(4700, 4900))
        _initCaps["automationName"] = "UiAutomator2"
        _initCaps["appPackage"] = 'cn.vsx.vc'
        _initCaps["appActivity"] = '.activity.RegistActivity'
        _initApp["Caps"] = _initCaps
        devices_list.append(_initApp)
    print(len(getDevices()))
    print(len(devices_list))
    return devices_list

run中,多进程调用启动命令行,并传递参数:

def runnerPool(device_list):
    getdevice = getDevices()
    with ProcessPoolExecutor(len(getdevice)) as pool:
        pool.map(runPytest, device_list)


def runPytest(device):
    print(f"cmdopt is {device}")
    report = f"report-{device['Caps']['deviceName']}".split(":", 1)[0]
    try:
        os.system(f"del /s /q E:\\appium-pytest\\{report}")
        time.sleep(1)
        os.system(f"rd /s /q E:\\appium-pytest\\{report}")
        time.sleep(1)
        print(f"{report} report has deleted")
    except:
        print("no directory existed")
    finally:
        print(f"pool run device is {device['devices']}")
        pytest.main(["../TestCases/", f"--cmdopt={device}", "--alluredir", f"../{report}/xml"])
        time.sleep(1)
        os.system(f"allure generate ../{report}/xml -o ../{report}/html")

conftest文件中,获取命令行传递过来的参数:

def pytest_addoption(parser):
    parser.addoption("--cmdopt", action="store", default="device", help="None")

@pytest.fixture(scope="session")
def cmdopt(request):
    return request.config.getoption("--cmdopt")

conftest中通过传递的参数,生成连接对象:

@pytest.fixture(scope="session")
def connectDevice(cmdopt):
    device = eval(cmdopt)
    device_caps = {}
    device_caps["platformVersion"] = getPhoneInfo(device["Caps"]["deviceName"])["release"]
    device_caps["platformName"] = "Android"
    device_caps["automationName"] = "UiAutomator2"
    device_caps["deviceName"] = device["Caps"]['deviceName']
    device_caps["udid"] = device["Caps"]['deviceName']
    device_caps["appPackage"] = "cn.vsx.vc"
    device_caps["appActivity"] = ".activity.RegistActivity"
    device_caps["noReset"] = True
    device_caps["noSign"] = True
    device_caps["unicodeKeyboard"] = True
    device_caps["resetKeyboard"] = True
    device_caps["systemPort"] = int(device["systemPort"])
    remote = "http://127.0.0.1:" + str(device["port"]) + "/wd/hub"
    print(f"wo shi pytest {device_caps}")
    driver = webdriver.Remote(remote, device_caps)
    return driver

测试用例中,使用对象来进行操作:

class Test_groupCall():
    @allure.feature("group_call")
    @allure.story("login")
    def test001_login(self, connectDevice):
        '''登入选择单位'''
        WebDriverWait(connectDevice, 10).until(
            lambda x: x.find_element_by_xpath(
                "//android.widget.TextView[contains(@text, '选择单位')]").is_displayed())  # 验证等待10秒超时
        x = connectDevice.get_window_size()['width']  # 获取当前屏幕宽
        y = connectDevice.get_window_size()['height']  # 获取当前屏幕高
        a, b = 170 / 768, 790 / 1184  # 选择单位222系数
        connectDevice.find_element_by_xpath("//android.widget.TextView[contains(@text, '选择单位')]").click()

最后:

多设备连接时,一定要注意给每个desired_caps中加入每个设备自己的systemPort,否则会连接不上多设备,至此改造成功,最后生成的报告也让人满意:

总结:

感谢每一个认真阅读我文章的人!!!

我个人整理了我这几年软件测试生涯整理的一些技术资料,包含:电子书,简历模块,各种工作模板,面试宝典,自学项目等。欢迎大家评论区留言或私我免费领取。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/654209.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

幼儿园门禁如何应用人脸识别技术?3大优势你知道几个

随着社会的发展和科技的进步,人脸识别技术逐渐渗透到各个领域,为我们的生活带来了许多便利和安全。在幼儿园这个特殊的场所,保证幼儿的安全和管理是至关重要的。 通过人脸识别技术,幼儿园可以准确、快速地辨识幼儿、家长和教职工的…

yolov8 目标检测与跟踪

参考: 参考: https://github.com/ultralytics/ultralytics https://github.com/TommyZihao/Train_Custom_Dataset/blob/main/%E7%9B%AE%E6%A0%87%E8%BF%BD%E8%B8%AA/%E5%85%AC%E5%BC%80%E8%AF%BE/ https://www.rstk.cn/news/42041.html?actiononClick …

Docker部署gitlab-runner

gitlab-runner 1.部署 Linux使用二进制的方式Docker中使用容器的方式启动gitlab-runnerHelm包的方式安装gitlab-runner Docker中使用容器的方式启动gitlab-runner 1.安装gitlab runner docker run -d --name gitlab-runner --restart always \ -v /srv/gitlab-runner/conf…

基于U-Net网络实现图像分割

目录 1、作者介绍2、U-Net网络及数据集介绍2.1 U-Net网络2.2 数据集介绍2.2.1 VOC_2012数据集2.2.2 眼球毛细血管数据集2.2.3 医学图像数据集 3、U-Net实现图像分割3.1 U-Net实现图像分割实验(简易版本)3.1.1 环境配置3.1.2 数据集准备3.1.3 代码实现3.1…

《项目实战》使用JDBC手写分库

文章目录 1、概要2、整体架构流程3、技术名词解释4、技术细节4.1、指定分库规则4.2、安装Mysql数据库以及建库建表4.3、创建Java项目4.3.1、使用 Idea创建Maven项目4.3.1.1、修改pom.xml配置 4.3.2、编写分库/路由规则 DbRouter4.3.3、编写数据库交互工具 DaoUtil4.3.4、编写数…

MyBits的创建与使用

文章目录 前言MyBits的优点这里简单回忆下用JDBC的流程 MyBits的调用流程MyBits的配置传递参数之# 与 $ 的区别 当mysql与程序属性映射不一致时的解决方案 前言 上篇博客讲述了 Spring后端与前端进行交互的过程, 而这篇博客将讲述Spring与数据库的交互 , 众所周知 后端与数据库…

1.1数据结构绪论

一、数据结构 学习如何使用程序代码把现实世界的问题信息化 二、数据的基本概 1、数据:信息的载体,是描述客观世界属性的数、字符及被计算机程序识别和处理的集合。 早期计算机处理的数据——纯数值类型;现代计算机处理数据——非数据类型 …

融合创新:AI虚拟数字人与3D VR全景引领未来旅游潮流

导语: 随着科技不断发展,AI虚拟数字人和3D VR全景技术的融合正引领着创新的潮流。这种融合不仅仅是对传统导览的升级,更为各个领域带来了全新的创新应用。让我们一起探索AI虚拟数字人与3D VR全景融合的创新应用,看看它们如何在多…

快速解决Github无法访问的问题

Github访问慢,是困扰很多人的问题,今天就出一个解决方案,按照下面思路,可以实现快速访问Github,来查看我们需要的资源。 目录 一、获取DNS 二、修改hosts文件内容 2.1 修改hosts权限 2.2 修改hosts内容 三、轻…

以指标驱动,企业数智化迈向新阶段

近年来,我国数字经济蓬勃发展,数据成为推动经济社会发展的新要素。国家十四五规划指出,要激活数据要素潜能,加快建设数字经济,需要重点实施“上云用数赋智”行动,推动数据赋能全产业链协同转型。为进一步迈…

保姆级教你用Python制作超级玛丽游戏“爷青回~”(文末赠书)

名字:阿玥的小东东 学习:Python、C/C 主页链接:阿玥的小东东的博客_CSDN博客-python&&c高级知识,过年必备,C/C知识讲解领域博主 目录 贪吃蛇游戏 弹珠游戏 超级玛丽(爷青回~) 完整代码如下: 总…

SpringBoot 实现 PDF 添加水印

SpringBoot 实现 PDF 添加水印 使用场景方式一:使用 Apache PDFBox 库方式二:使用 iText 库方式三:Free Spire.PDF for JavaDemo 使用场景 PDF(Portable Document Format,便携式文档格式)是一种流行的文件…

LIME论文阅读笔记

这是暗图增强领域一篇经典的传统方法论文,发表在TIP这个顶刊 文章基于的是这样一个公式: L R ⋅ T LR\cdot T LR⋅T 其中, L L L是暗图, R R R是反射分量, T T T是illumination map,并且对于彩色图像来说…

OpenCV reshape函数

reshape函数 在opencv中,reshape函数比较有意思,它既可以改变矩阵的通道数,又可以对矩阵元素进行序列化,非常有用的一个函数。 函数原型: C: Mat Mat::reshape(int cn, int rows0) const参数比较少,但设…

DJ3-5 TCP:流量控制、连接控制

目录 一、流量控制 二、连接管理 1. 建立连接(三次握手) 2. 关闭连接 3. TCP 连接的生命周期 一、流量控制 一条 TCP 连接的每一侧主机都为该连接设置了接收缓冲区。 TCP 的接收方的接收缓冲区: 1. 提供流量控制服务的原因 应用进程会…

Burpsuit使用03:拦截请求并修改响应

burpsuite是渗透的必备工具,使用它可以进行一些截包分析,修改包数据、暴力破解、扫描等功能,使用最多的场景应该是设置代理拦截数据包分析数据和爆破。 文章目录 拦截请求并修改响应Intercept is offForwardDropAction 拦截请求并修改响应 拦…

5.4、docker-compose

h ttps://www.runoob.com/docker/docker-compose.html Docker Compose docker-compose.yml 配置文件编写详解_docker-compose.yml 编写_种子选手的博客-CSDN博客 docker-compose.yml 配置文件编写详解 1.dockerfile: 构建镜像; 2.docker run: 启动容器;…

upyter Notebook:内核似乎挂掉

项目场景:提示:这里简述项目相关背景:项目场景:深度强化学习在中国股票量化交易上的应用,要求跑赢大盘问题描述提示:这里描述项目中遇到的问题:使用Jupyter Notebook运行时,跑到绘图…

瑞萨RA系列mcu学习笔记--RTT-pwm驱动

方案1:Studio 2.2.6和使用了RASC3.5下使用pwm驱动 开发环境必须说一下,本人在在开发环境的问题上栽了一个跟头, 使用最新版的RTT Studio 2.2.6和使用了RASC4.0的版本生成的公共编译ok,但是一下载到mcu就直接不能运行&#xff1a…

浅谈Java的IO与Netty

一、Java的IO((Input/Output))模型 传统IO和Java NIO最大的区别是传统的IO是面向流,NIO是面向Buffer Socket之间建立链接及通信的过程!实际上就是对TCP/IP连接与通信过程的抽象: 1.服务端Socket会bind到指定的端口上,Listen客户端的”插入”…