使用 Pytest 运行 yaml 文件来驱动 Appium 自动化测试

news2024/12/27 1:08:26

目录

前言:

获取 yaml 文件

YamlTest 测试类

Appium 初始化

Pytest 测试类

自定义 runtest demo:

自定义错误输出

Yaml 使用方式规则


前言:

使用Pytest来运行yaml文件来驱动Appium自动化测试是一种方便且灵活的方法。通过将测试数据和测试逻辑分离,您可以更轻松地管理和扩展测试用例。

本文主要介绍一下 pytest hook 方法是怎么运行 yaml 文件做测试的 (喜欢其他方式也可以用 xlsx,sql 等),怎么与 Appium 结合,来驱动 Appium 做自动化测试。

该运行方式参照 pytest --doctest 参数运行的方法, 想深入了解的同学可以查看 _pytest/doctest.py 源码

获取 yaml 文件

使用 pytest_collect_file 钩子函数,在脚本运行之前过滤 .yml 文件

def pytest_collect_file(parent, path):
    # 获取文件.yml 文件
    if path.ext == ".yml" and path.basename.startswith("test"):
        return YamlFile(path, parent)

读取 yml 转成 json 移交至 YamlTest 类

class YamlFile(pytest.File):
    # 读取文件内容
    def collect(self):
        import yaml
        raw = yaml.safe_load(self.fspath.open(encoding='utf-8'))
        for name, values in raw.items():
            yield YamlTest(name, self, values)

YamlTest 测试类

下面就是测试类了,这里我们 Appium 还是使用单例初始化,方便所有测试用例继承一个 session

Appium 初始化

class Singleton(object):
    """单例 
    ElementActions 为自己封装操作类"""
    Action = None

    def __new__(cls, *args, **kw):
        if not hasattr(cls, '_instance'):
            desired_caps={}
            host = "http://localhost:4723/wd/hub"
            driver = webdriver.Remote(host, desired_caps)
            Action = ElementActions(driver, desired_caps)
            orig = super(Singleton, cls)
            cls._instance = orig.__new__(cls, *args, **kw)
            cls._instance.Action = Action
        return cls._instance

class DriverClient(Singleton):
    pass

Pytest 测试类

测试类初始化,这里要说一下,测试类一定要继承 pytest.Item 方法

class YamlTest(pytest.Item):
    def __init__(self, name, parent, values):
        super(YamlTest, self).__init__(name, parent)
        self.values = values
        self.Action = DriverClient().Action # 初始化 Appium
        self.locator = None

为了减少代码的逻辑,取出来的 yaml json 字符串怎么可以直接转化成可运行方法呢?

这里就要说到 class 的 _getattribute_ 内建属性的用法,下面举个简单例子

class TestExample:
    def test1(self):
        print('test1')

>>> TestExample().__getattribute__('test1')()
test1

现在我们就能直接读取 yaml 文件中的 method 字符串直接转化成 Appium api 运行了(method 对应自己封装或 Appium api 的方法)

自定义 runtest demo:

class YamlTest(pytest.Item):
    def __init__(self, name, parent, values):
        super(YamlTest, self).__init__(name, parent)
        self.values = values
        self.Action = DriverClient().Action
        self.locator = None

    def runtest(self):
        # 运行用例
        for self.locator in self.values:
            self.locator['time'] = 5
            if self.locator.get('element'):
                # 需要接收参数
                response = self.Action.__getattribute__(self.locator.get('method'))(self.locator)
            else:
                # 不需要参数
                response = self.Action.__getattribute__(self.locator.get('method'))()
            self.assert_response(response, self.locator)


这里将 Appium api 基本操作封装成了两类:

  • 需要接收元素的参数,例如:点击,查找,输入等
  • 不需要接收元素参数,例如:重启,滑动等

自定义错误输出

def repr_failure(self, excinfo):
    """自定义报错信息,如果没有定义则会默认打印错误堆栈信息,因为比较乱,所以这里自定义一下 """

    if isinstance(excinfo.value, Exception):
        return '测试用例名称:{} \n' \
               '步骤输入参数:{} \n' \
               '数据:{}'.format(self.name, self.locator, excinfo.value.args)

def reportinfo(self):
    return self.fspath, 0, "CaseName: %s" % self.name

下面就是完整的测试类了

class YamlTest(pytest.Item):
    def __init__(self, name, parent, values):
        super(YamlTest, self).__init__(name, parent)
        self.values = values
        self.Action = DriverClient().Action
        self.locator = None

    def runtest(self):
        # 运行用例
        for self.locator in self.values:
            self.locator['time'] = 5
            is_displayed = True
            if not self.locator.get('is_displayed'):
                is_displayed = False if str(self.locator.get('is_displayed')).lower() == 'false' else True
            try:
                if self.locator.get('element'):
                    response = self.Action.__getattribute__(self.locator.get('method'))(yamldict(self.locator))
                else:
                    response = self.Action.__getattribute__(self.locator.get('method'))()
                self.assert_response(response, self.locator)
            except Exception as E:
                if is_displayed:
                    raise E
                pass

    def repr_failure(self, excinfo):
        """自定义报错信息,如果没有定义则会打印堆栈错误信息,调试时可以注释该函数,便于问题查找 """
        if isinstance(excinfo.value, Exception):
            return '测试类名称:{} \n' \
                   '输入参数:{} \n' \
                   '错误信息:{}'.format(self.name, self.locator, excinfo.value.args)

    def assert_response(self, response, locator):
        if locator.get('assert_text'):
            assert locator['assert_text'] in response
        elif locator.get('assert_element'):
            assert response

    def reportinfo(self):
        return self.fspath, 0, "CaseName: %s" % self.name

这里我们主体 Pytest+yaml 测试框架就构建完成了,当然还有各种异常的捕获等钩子函数,自己封装的 Appium api 方法等,上篇文章讲过了,这里就不赘述了,自行选择添加更多功能

Yaml 使用方式规则

因为我们上面将接收方法分成了需要 element 参数和不需要 element 参数两类所以 yaml 格式如下

test_index:
  -
    method: launchApp # 启动 APP
  -
    method: 方法名称 例如:click (必填)
    element: 查找元素id,class等 (选填,配合 method 如需要点击元素,查找元素等必填)
    type: 元素类型 id,xpath,class  name,accessibility id (选填,会自动识别,如识别错误则自行填写)
    name: 测试步骤的名称 例如:点击搜索按钮 (选填)
    text: 需要输入或者查找的文本 (选填,配合部分 method 使用)
    time: 查找该元素需要的时间,默认 5s (选填)
    index: 页面有多个id,class时,不为空则查找元素数组下标 (选填)
    is_displayed: 默认 True ,当为 False 时元素未找到也不会抛异常(选填)

咱们用微博做个 demo 测试一下

test_index:
  -
    method: launchApp # 重启 APP
  -
    method: click
    element: click_ad_skip
    name: 广告跳过按钮
    is_displayed: False
  -
    method: click
    element: 发现
    name: 导航发现按钮
  -
    method: sleep
    element: 3
  -
    method: set_text
    element: com.sina.weibo:id/tv_search_keyword
    text: testerhome
    name: 搜索输入框
  -
    method: set_keycode_enter
  -
    method: screenshot_element
    element: //*[@resource-id="com.sina.weibo:id/lv_content"]/android.widget.RelativeLayout[1]
    name: 搜索内容截图

运行用例

pytest -v ./test_case/test_ranking.yml --alluredir /report/test

或者直接运行文件目录

使用方法和基本 pytest 用法没有太大区别

pytest -v ./test_case --alluredir /report/test

来查看下运行结果:

 

  作为一位过来人也是希望大家少走一些弯路

在这里我给大家分享一些自动化测试前进之路的必须品,希望能对你带来帮助。

(WEB自动化测试、app自动化测试、接口自动化测试、持续集成、自动化测试开发、大厂面试真题、简历模板等等)

相信能使你更好的进步!

点击下方小卡片

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

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

相关文章

【异常解决】postman请求提示Full authentication is required to access this resource

Full authentication is required to access this resource解决办法 报错问题:在使用 postman 测试接口时,该接口需要在 Header 中传入 access_token,实际上也在请求的 Header 中添加上了 access_token 参数,但是服务端还是返回4…

【STM32零基础入门教程01】STM32入门基础知识

本篇内容为STM32零基础入门教程的第一篇,网上STM32的教程很多,有些初学者还是望而却步。其实STM32并不难,只是一个新的事物出现在我们面前一时间不适应,思来想去我打算写点东西一方面自己有点知识的积累,另一方面希望可…

Python教程(4)——Python开发工具PyCharm的下载与安装

PyCharm是一种专业的Python集成开发环境(IDE),由JetBrains公司开发和维护。它提供了丰富的功能和工具,帮助开发人员更高效地编写、调试和测试Python代码。如果是一些大型Python项目强烈推荐用这个来开发。今天我们来介绍一下PyCha…

【实战】 七、Hook,路由,与 URL 状态管理(中) —— React17+React Hook+TS4 最佳实践,仿 Jira 企业级项目(十二)

文章目录 一、项目起航:项目初始化与配置二、React 与 Hook 应用:实现项目列表三、TS 应用:JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook&…

Docker基础(二)

1、Docker工作原理 Docker是一个Clinet-Server结构的系统,Docker守护进程运行在主机上,然后通过Socket连接从客户端访问,守护进程从客户端接受命令并管理运行在主机上的容器。 容器,是一个运行时环境,就是我们前面说的…

论文笔记:Deep Spatio-Temporal Residual Networks for Citywide Crowd FlowsPrediction

2017 AAAI 使用时空残差网络ST-ResNet 进行 城市区域流入流出客流量预测 1 研究对象 城市客流流入流出 根据经纬度将城市划分为网格 IJ 1.1 难点 空间依赖性 时间依赖性 外部影响 2 模型 3 实验 北京出租车数据纽约自行车数据 评价指标:RMSE

Java List中通过对象属性排序,可实现多条件排序

直接上代码: import com.google.common.collect.Lists; import lombok.AllArgsConstructor; import lombok.Data;import java.util.Comparator; import java.util.List; import java.util.stream.Collectors;/*** List 对象属性排序*/Data AllArgsConstructor clas…

[java安全]动态代理

文章目录 【java安全】动态代理前言本质重要方法Proxy#newProxyInstance()InvocationHandler#invoke() 举例 【java安全】动态代理 前言 java中代理分为两种:静态代理、动态代理 而动态代理又分为:jdk动态代理、CGLIB动态代理 本文我们来谈谈jdk动态代…

Iceberg从入门到精通系列之十七:Apache InLong往Iceberg同步数据

Iceberg从入门到精通系列之十七:Apache InLong往Iceberg同步数据 一、概览二、版本支持三、依赖项四、SQL API 用法五、多表写入六、动态表名映射七、动态建库、建表八、动态schema变更九、Iceberg Load 节点参数十、数据类型映射 一、概览 Apache Iceberg是一种用…

【机器学习算法】主成分分析(PCA)

主成分分析(PCA) PCA(Principal Component Analysis) 是实现数据降维的一种算法。正如其名,假设有一份数据集,每条数据的维度是d,PCA通过分析这d个维度的前k个主要特征(这k个维度在原有d维特征的基础上重新构造出来,且是全新的正交…

SpringBoot+React学科竞赛管理系统 附带详细运行指导视频

文章目录 一、项目演示二、项目介绍三、运行截图四、主要代码 一、项目演示 项目演示地址: 视频地址 二、项目介绍 项目描述:这是一个基于SpringBootReact框架开发的学科竞赛管理系统。首先,这是一个前后端分离的项目,代码简洁…

初学者怎么学习c++(合集)

学习c方法1 找一本好的书本教材,辅助看教学视频。好的教材,可以让你更快更好的进入C/C的世界。在校学生的话,你们的教材通常都是不错的。如果是自学,推荐使用谭浩强出的C/C经典入门教材。看视频是学习比较直观的方式。建议先看课本…

从零开始理解Linux中断架构(20)--关于二级中断控制-链式chained Handler

二级中断控制器是个双重角色,在上级中断控制器看来他是个中断设备,在连接到他的下级设备来看,他是个中断控制器。所以处理完成基本的中断控制器管理功能:映射本地中断,还要多个动作:修改上级中断的默认irq Handler,向上级中断设置自己的链式中断处理函数。 中断控制的层…

Springboot实现过滤器

一、导言 在Spring Boot中,过滤器是一种用于对HTTP请求进行预处理和后处理的组件。相较于拦截器,过滤器属于Servlet规范的一部分,它能够在请求进入Web容器之前或返回给客户端之前进行操作。 要在Spring Boot中实现过滤器,可以按…

指针进阶(万字深层次指针解析)

❤️ 作者简介 :对纯音乐情有独钟的阿甘 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识,对纯音乐有独特的喜爱 📗 日后方向 : 偏向于CPP开发以及大数据方向,如果你也感兴趣的话欢迎关注博主,期待更新 指针进阶 …

Java正则表达式,不定期更新

Java正则表达式 1. 匹配数字(包含负数、小数)2. 匹配不是纯数字和纯字母且需要8位以上的密码3. 密码:字母、数字、符号(_-*.,!#符号可自定义)三选二4. 密码:必须包含大写、小写、数字、符号(_-*…

车道线检测|利用边缘检测的原理对车道线图片进行识别

前言 那么这里博主先安利一些干货满满的专栏了! 这两个都是博主在学习Linux操作系统过程中的记录,希望对大家的学习有帮助! 操作系统Operating Syshttps://blog.csdn.net/yu_cblog/category_12165502.html?spm1001.2014.3001.5482Linux S…

工程监测振弦采集仪的解决方案案例解释

振弦采集仪是一种用于测量结构物的振动状态和应力变化的高精度仪器,广泛应用于建筑、桥梁、隧道、地铁等工程领域。以下是一些常见的解决方案案例分析: 基础监测方案:对于大型建筑或桥梁工程,需要对基础进行实时监测。使用振弦采集…

System类 BigInterger BigDecimal

System类 常用方法和案例 exit: 退出当前程序 System.out.println("zhang"); // 0表示一个正常退出的状态 System.exit(0); System.out.println("cheng");System.arraycopy: 复制数组元素,比较适合底层的调用&#xf…

基于linux下的高并发服务器开发(第二章)- 2.2 进程状态转换

01 / 进程的状态 (1)三态模型 进程状态分为三个基本状态,即就绪态,运行态,阻塞态 (2)五态模型 在五态模型中,进程分为新建态,就绪态,运行态,阻…