PageObject+Python+Appium

news2024/12/1 5:31:11

目录

前言:

简介

功能

常用目录

配置

实例 - 第一次启动 app

实例 - 登录

代码入口实例

结果展示


前言:

Page Object模式是一种常用的设计模式,用于组织和管理自动化测试脚本中的页面对象。它将页面的元素和操作封装在一个独立的类中,使测试脚本更加模块化、可维护和可重用。

简介

  • 基于 appium+python3 封装的自动化测试框架

功能

  • python3
  • unittest 参数化
  • pageobject
  • 数据维护用的 YMAL
  • excel 的测试报告
  • 支持多设备 andoird 并行
  • 支持 webview

常用目录

  • Base 封装常用方法
  • Log 记录不同设备的操作用例的日志,操作失败的截图
  • PageObject 放 page
  • test 目录写测试用例
  • runner 运行入口

配置

配置 run.yaml

app: Jianshu.apk

配置 devices.yaml

- devices:  emulator-5554
  port: 4724
  config: appium --session-override  -p 4724 -bp 4734 -U  emulator-5554
  platformName: android
- devices: DU2TAN15AJ049163
  port: 4725
  config: appium --session-override  -p 4725 -bp 4735 -U  DU2TAN15AJ049163
  platformName: android

实例 - 第一次启动 app

配置用例 yaml

testinfo:
    - id: test001
      title: 第一次打开
testcase:
    - operate_type: swipeLeft
      time: 4
      element_info: android.widget.ImageView
      find_type: class_name
    - element_info: com.jianshu.haruki:id/tv_enter
      find_type: id
      operate_type: click
check:
    - element_info: com.jianshu.haruki:id/btn_login
      find_type: id

PageObject

class FirstOpen:
    '''
    kwargs: WebDriver driver, String path(yaml配置参数)
    isOperate: 操作失败,检查点就失败
    testInfo:
    testCase:
    '''

    def __init__(self, **kwargs):
        self.driver = kwargs["driver"]
        self.path = kwargs["path"]
        self.operateElement = OperateElement(self.driver)
        self.isOperate = True
        self.testInfo = getYam(self.path)["testinfo"]
        self.testCase = getYam(self.path)["testcase"]


    '''
    操作步骤
    logTest 日记记录器
    '''

    def operate(self, logTest):
        for item in self.testCase:
            result = self.operateElement.operate(item, self.testInfo, logTest)

            if not result:
                print("操作失败")
                self.isOperate = False
                break

    '''
    检查点
    caseName:函数名
    logTest 记录日志:一个手机记录单独记录一个日志
    '''

    def checkPoint(self, caseName, logTest, devices):
        result = False
        if not self.isOperate:
            print("操作失败,检查点失败")
            # return self.isOperate
        else:
            check = getYam(self.path)["check"]
            result = self.operateElement.findElement(check)  # 检查点

        countSum(result)
        countInfo(result=result, testInfo=self.testInfo, caseName=caseName, driver=self.driver, logTest=logTest, devices=devices)
        return result

test

PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class FirstOpenTest(ParametrizedTestCase):
    def testFirst(self):
        firsOpen = FirstOpen(driver=self.driver, path=PATH("../yaml/firstOpen.yaml"))
        firsOpen.operate(logTest=self.logTest)
        firsOpen.checkPoint(caseName=self.__class__.__name__, logTest=self.logTest, devices=self.devices["deviceName"])


    def setUp(self):
        super(FirstOpenTest, self).setUp()

实例 - 登录

配置 yaml

testinfo:
    - id: test0002
      title: 登录
testcase:
    - element_info: com.jianshu.haruki:id/btn_login
      find_type: id
      operate_type: click
    - element_info: com.jianshu.haruki:id/et_tel
      find_type: id
      operate_type: set_value
      text: username
    - element_info: com.jianshu.haruki:id/et_password
      find_type: id
      operate_type: set_value
      text: pwd
    - element_info: com.jianshu.haruki:id/btn_register_1
      find_type: id
      operate_type: click
    - element_info: //android.widget.ImageView[@index='0']
      find_type: xpath
      operate_type: click
check:
    - element_info: com.jianshu.haruki:id/add_subscribe
      find_type: id
    - element_info: com.jianshu.haruki:id/tab_more
      find_type: id

PageObject

class Login:
    '''
    kwargs: WebDriver driver, String path(yaml配置参数)
    isOperate: 操作失败,检查点就失败
    testInfo:
    testCase:
    '''

    def __init__(self, **kwargs):
        self.driver = kwargs["driver"]
        self.path = kwargs["path"]
        self.operateElement = OperateElement(self.driver)
        self.isOperate = True
        self.testInfo = getYam(self.path)["testinfo"]
        self.testCase = getYam(self.path)["testcase"]

    '''
    操作步骤
     logTest 日记记录器
    '''

    def operate(self, logTest):
        for item in self.testCase:
            result = self.operateElement.operate(item, self.testInfo, logTest)

            if not result:
                print("操作失败")
                self.isOperate = False
                break
    '''
    检查点
    caseName:测试用例函数名 用作统计
    logTest: 日志记录
    devices 设备名
    '''

    def checkPoint(self, caseName, logTest, devices):
        result = False
        if not self.isOperate:
            print("操作失败,检查点失败")
        else:
            check = getYam(self.path)["check"]
            result = self.operateElement.findElement(check)  # 检查点

        countSum(result)
        countInfo(result=result, testInfo=self.testInfo, caseName=caseName, driver=self.driver, logTest=logTest, devices=devices)
        return result

test

PATH = lambda p: os.path.abspath(
    os.path.join(os.path.dirname(__file__), p)
)


class LoginTest(ParametrizedTestCase):

    def testLogin(self):
        login = Login(driver=self.driver, path=PATH("../yaml/login.yaml"))
        login.operate(logTest=self.logTest)
        login.checkPoint(caseName=self.__class__.__name__, logTest=self.logTest, devices=self.devices["deviceName"])

    # def testWrongPwd(self):
    #     pass

    def setUp(self):
        super(LoginTest, self).setUp()

代码入口实例

def runnerCaseApp(devices):
    starttime = datetime.now()
    suite = unittest.TestSuite()
    suite.addTest(ParametrizedTestCase.parametrize(FirstOpenTest, param=devices)) # 引用不同的测试类
    suite.addTest(ParametrizedTestCase.parametrize(LoginTest, param=devices)) # 引用不同的测试类
    unittest.TextTestRunner(verbosity=2).run(suite)
    endtime = datetime.now()
    countDate(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), str((endtime - starttime).seconds) + "秒"

    ...


if __name__ == '__main__':
    if AndroidDebugBridge().attached_devices():
        getDevices = init()
        appium_server = AppiumServer(getDevices)
        appium_server.start_server()
        while not appium_server.is_runnnig():
            time.sleep(2)
        runnerPool(getDevices)
        appium_server.stop_server()
        writeExcel()
    else:
        print(u"设备不存在")

结果展示

日志目录

文件夹:samsung_GT-I9500_android_4.4,包含截图

2017-06-07 19:39:35,972  - INFO - ----  test001_第一次打开_android.widget.ImageView   START     ----
2017-06-07 19:39:44,433  - INFO - [CheckPoint_1]: FirstOpenTest: NG
2017-06-07 19:40:02,013  - INFO - ----  test0002_登录_com.jianshu.haruki:id/btn_login   START     ----
2017-06-07 19:40:03,075  - INFO - ----  test0002_登录_com.jianshu.haruki:id/et_tel   START     ----
2017-06-07 19:40:07,460  - INFO - ----  test0002_登录_com.jianshu.haruki:id/et_password   START     ----
2017-06-07 19:40:08,480  - INFO - ----  test0002_登录_com.jianshu.haruki:id/btn_register_1   START     ----
2017-06-07 19:40:13,640  - INFO - ----  test0002_登录_//android.widget.ImageView[@index='0']   START     ----

测试报告

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

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

(软件测试相关资料,自动化测试相关资料,技术问题答疑等等)

相信能使你更好的进步!

点击下方小卡片

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

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

相关文章

数据质量相关问题系列

数据质量问题是什么? 数据质量,是指在业务环境下,数据符合数据消费者的使用目的,能满足业务场景具体需求的程度。而数据质量问题是指数据集中存在无法容忍的缺陷,从而降低该数据的可靠性和可信度。简单理解就是数据很脏…

【JAVA】云HIS系统功能菜单知识(一)

一、云HIS特色 云HIS滚动消息栏:质控消息、住院时长、药库结转、患者入院、医嘱停止、新开医嘱、门诊用药不良、出院审核、药品调拨、排班提醒、药品库存、药品过期、药品临期等帮助医生、护士和相关管理人员实时接收院内消息并作出处理。 二、云HIS功能菜单 【预约…

【MySQL】MySQL事务保姆级教程(适合MySQL初学者学习)

🧑‍💻作者名称:DaenCode 🎤作者简介:啥技术都喜欢捣鼓捣鼓,喜欢分享技术、经验、生活。 😎人生感悟:尝尽人生百味,方知世间冷暖。 📖所属专栏:重…

桥接模式——连接抽象维度和实现维度

桥接模式 bridge pattern 一 定义 桥接模式,是将抽象部分与它的具体实现部分分离,使它们都可以独立地变化。它是将两个不同的维度建立联系。这两个维度通常是指:抽象维度和实现维度。 使用场景 在抽象和具体实现之间需要增加更多的灵活性…

找不到dll的问题解决,loadlibrary 126错误

症状:loadlibrary时,getlasterror返回126,表示是找不到模块错误。来到目录下看到依赖所需的dll均存在 解决办法: 1.下载ProcmonProcmom-监视进程所有的动作资源-CSDN文库https://download.csdn.net/download/gergul/880597622.运…

RocketMQ第四节(部署模式、监控面板等)

1:mq的部署模式 部署方式 | RocketMQ 参考官网。 单机模式:抗风险能力差,单机挂机没服务,单机硬盘损坏,丢失数据 多机(多master没有Slave副本): 多个master采用RAID10磁盘,不会丢…

[java安全]类加载器CommonsCollections3

文章目录 【java安全】类加载器&CommonsCollections3前言java类加载器URLClassLoader利用ClassLoader#defineClass()直接加载字节码 使用TemplatesImpl加载字节码TemplatesImpl中字节码实现AbstractTranslet类 构造未完成POCTrAXFilter类调用newTransformer()InstantiateTr…

【AI绘画Stable Diffusion】高清图像放大+面部修复+一键抠图,谈谈你可能不知道的优化技巧!

一提起后期处理,我猜你可能立马想到的就是图像放大。 今天,我要向你展示的后期处理手法,以及优化技巧。 图片放大算法 如果你常用的是秋叶大佬的整合包,那么你对"R-ESRGAN 4x"和"R-ESRGAN 4x Anime6B"应该…

FPGA单端口RAM——IP核

文章目录 前言一、RAM简介1、随机存储器IP核分类1、RAM IP核2、ROM IP核 2、RAM IP核 二、IP核配置步骤三、源码1、ram_rw驱动文件2、ip_1port_ram顶层文件3、仿真文件4、仿真波形 四、SignalTap II在线调试五、总结六、参考资料 前言 环境: 1、Quartus18.1 2、vsco…

Leetcode-每日一题【1019.链表中的下一个更大结点】

题目 给定一个长度为 n 的链表 head 对于列表中的每个节点,查找下一个 更大节点 的值。也就是说,对于每个节点,找到它旁边的第一个节点的值,这个节点的值 严格大于 它的值。 返回一个整数数组 answer ,其中 answer[…

Servlet的监听器

Servlet常用的监听器 ServletContextAttributeListener 用来感知ServlerContext对象属性变化,比如添加或删除属性变化 ServletContextListener 用来感知ServlerContext对象的创建和销毁的 ServletRequestListener 可以用来监听感知ServletRequest对象的创建和销毁的…

大语言模型(LLM)评估综述

论文地址:https://arxiv.org/abs/2307.03109 Github地址:https://github.com/MLGroupJLU/LLM-eval-survey 一 、背景 随着ChatGPT和GPT-4的推出,大型语言模型(LLM)在学术界和工业界的热度日益升高,这主要…

优雅的设计测试用例

⭐️前言⭐️ 入职以后接触到了公司的具体业务,提升了设计测试用例的能力,于是沉淀出这篇文档与大家分享。 🍉欢迎点赞 👍 收藏 ⭐留言评论 📝私信必回哟😁 🍉博主将持续更新学习记录收获&…

Acwing.905 区间选点(贪心)

题目 给定N个闭区间[a,bi],请你在数轴上选择尽量少的点,使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数N,表示区间数。 接下来N行,每行包含两个整数…

Linux内核《CPU负载计算》

目录 前言一、什么是CPU负载?二、如何计算CPU负载三、计算CPU负载的一个脚本四、top命令详解 前言 在实际的产品开发中,我们往往需要关注CPU的负载,确保程序可以长久稳定的运行,并且能够重复发挥SOC的性能。Linux中提供了一些命令…

ArrayList和LinkedList

ArrayList的注意事项 1、在ArrayList中可以放任意元素,包括空值,任何元素,且可重复添加。 2、ArrayList底层是由数组来实现数据存储的 3、ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高),看源码 在多线程的…

【Linux系列P7】进度条小程序的深度解剖(细节满满)

​​​​​ ​ 前言 大家好吖,欢迎来到 YY 滴 Linux系列 ,热烈欢迎! 本章主要内容面向接触过Linux的老铁,主要内容含 欢迎订阅 YY滴Linux专栏!更多干货持续更新!以下是传送门! 订阅专栏阅读&am…

SpringBoot项目中MVC使用--【SB系列之010】

SpringBoot系列文章目录 SpringBoot 的项目编译即报错处理–SB系列之001 —第一部的其它章节可以通过001链接 SpringBoot项目中WEB页面放哪里–【SB系列之008】 SpringBoot项目中WEB与Controller的联系–【SB系列之009】 ———————————————— 文章目录 SpringBoo…

线程池学习(五)线程工厂、线程池工厂

Executors 定义的Executor, ExecutorService, ScheduledExecutorService, ThreadFactory和Callable类的工厂和实用程序方法,我们称为线程池工厂。ThreadFactory 为定制化创建新线程的对象,我们称为线程工厂 前面几期的学习中,我已经初步会使用线程池了&…

用于公司文件防泄密用的保密软件(企业数据防泄密软件)

防止公司文件泄露是指采取各种措施和方法,以防止公司的敏感和机密文件被未经授权的人员获取、泄露或滥用的行为。 这些文件可能包含公司的商业机密、客户数据、财务信息、研发成果等重要资料,如果泄露给竞争对手、黑客或其他恶意人员,可能会对…