【python自动化】使用关键字驱动实现appium自动化

news2025/7/21 10:55:50

在写app自动化用例时,尝试用了关键字驱动的框架

        记录一下自己对关键字驱动的理解

        1 关键字驱动指将用例步骤的操作封装为关键字,比如定位元素、点击元素、获取元素属性值、断言,这些都是操作关键字

        2 在excel中按照用例执行过程,填写操作关键字以及要执行操作指令需要用到的参数信息及操作后保存的对象名

        3 封装的代码框架,可以实现读取excel用例文件,拿到关键字操作及对应的参数

        4 然后按照关键字动作传入对应的参数,去执行

关键点:

1)将用例步骤抽象出关键字

2)怎么执行excel中存放的字符串对应的方法

3)怎么将执行的结果存放到excel指定名称的变量

关键点的解决思路:

1)抽象关键字这一点:

ui用例主要的动作就是找元素、点击、输入、执行脚本、断言、获取属性,其他特殊的需要单独取思考封装

在模型中按照具体的action类型去判断:

if action_ == 'find':

#执行find_element

if action_ =='send_keys':

#对指定元素做输入操作

2)怎么执行excel中存放的字符串对应的方法

这里使用的是string的反射机制、利用类对象的__getattribute__(funcname)()实现动态调用类对象的方法

比如:find操作分为find_element、find_elements,那怎么让driver执行具体的函数?

driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_)

其中find_是获取的excel定义的调用哪个find方法,值是find_element、find_elements

driver.__getattribute__(find_)就是返回find_element或find_elements函数的引用,就是driver.find_element()或driver.find_elements

getattr(AppiumBy,selector_)是按照excel中指定的定位类型XPATH、ID动态获取AppiumBy类变量值

driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_)就等于

driver.find_elements(AppiumBy.ID,selector_value_)    假设selector_是ID

 3)怎么将执行的结果存放到excel指定名称的变量?

先解释一下场景:

通过driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_)返回了一个Weblement对象,需要赋值变量名为excel中定义的save_object值。假设save_object的值为ele1

如果直接写save_object =driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_)

那save_object 这个变量的值的appUI 元素,而不是ele1=ui元素赋值

如何给指定变量名的变量赋值?

可以通过自定义一块空间,然后对内存空间进行属性名、属性值的赋值 setattr()

实例化类的时候就会申请一块空间

故创建一个Context类,在需要赋值给设定的变量时

使用setattr(context,destname,destvalue)去设定,还是看刚才的例子,可以通过下面代码将find_element()返回的元素赋值给save_obj_指定的变量名

setattr(Context,save_obj_,driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_))

后续通过getattr(context,obj_name)拿到obj_name这个变量名的值

下面是具体的框架实现,仅简单实现了3个用例,(关键字驱动的util中没有做封装,侧重理解如何实现关键字驱动)

关键字驱动用例的excel文件:

 关键字驱动的关键执行方法:

'''
关键字驱动
'''
import xlrd
from appium.webdriver import WebElement
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.webdriver import WebDriver

from util.assertUtil import AssertUtil


class Context():
    pass
def runexcel_case(driver: WebDriver,casename):
    file = xlrd.open_workbook(filename = 'E:/pythonProjects/appproject/device.xlsx')
    sheet = file.sheet_by_name(casename)
    case_key = sheet.row_values(0)
    rownum = sheet.nrows
    case=[]
    #获取所有用例步骤
    for i in range(1,rownum):
        data = sheet.row_values(i)
        case.append(dict(zip(case_key,data)))
    for step in case:
        action_ = step.get('action',None)#如果用step['action'],当step没有action会抛异常,action指操作有定位元素、点击、输入等操作
        find_ = step.get('find', None)# 定位元素,是find_element、还是find_elements
        selector_ = step.get('selector', None)#定位元素的类型
        selector_value_ = step.get('selector_value', None)#定位元素的值
        save_obj_ = step.get('save_object', None)#将操作的结果保存的对象名
        operate_obj_ = step.get('operate_object', None)#对哪个对象进行操作
        inputtext_ = step.get('inputtext', None)#输入操作的驶入内容
        attribute_value_ = step.get('attribute_value', None)#获取对象什么属性
        if action_ == 'find':
            if save_obj_:
                if selector_ and selector_value_:
                    # driver.find_element(getattr(AppiumBy,selector_),selector_value_)#使用getattr(AppiumBy,selector_) 将excel定义的ID、XPATH按照字符串取到AppiumBy中对应的定位值
                    setattr(Context,save_obj_,driver.__getattribute__(find_)(getattr(AppiumBy,selector_),selector_value_))#driver.__getattribute__(find_)通过对象按照传入的参数,执行对象指定的方法,
                    # 如果是find_element就执行find_element,如果是find_elements就执行find_elements,
                    #思考: 需要考虑将find查找到的对象用save_object定义的变量名的变量去接收,需要自定义一块空间,然后利用setattribute将值赋给指定的变量
                else:
                    raise ValueError('在用例文件{}行缺少定义selector_或selector_value_的值'.format(case.index(step)))
                pass
            else:
                raise ValueError('在用例文件{}行缺少定义save_obj的值'.format(case.index(step)))
        if action_ == 'click':
            if operate_obj_:
                getattr(Context,operate_obj_).__getattribute__(action_)()
            else:
                raise ValueError('在用例文件{}行缺少定义operate_obj_的值'.format(case.index(step)))
        if action_ =='send_keys':
            if operate_obj_:
                if inputtext_:
                    getattr(Context, operate_obj_).__getattribute__(action_)(inputtext_)
                else:
                    raise ValueError('在用例文件{}行缺少定义inputtext_的值'.format(case.index(step)))
            else:
                raise ValueError('在用例文件{}行缺少定义operate_obj_的值'.format(case.index(step)))
        if action_ =='get_attribute':
            if save_obj_:
                if operate_obj_ :
                    if attribute_value_:
                        ele_obj = getattr(Context,operate_obj_)
                        if isinstance(ele_obj,WebElement):#如果是find_element返回的是单个元素
                            setattr(Context,save_obj_,ele_obj.__getattribute__(action_)(attribute_value_))
                        if isinstance(ele_obj, list):#如果是find_elements返回的是list
                            setattr(Context,save_obj_,[i.__getattribute__(action_)(attribute_value_)for i in ele_obj])
                    else:
                        raise ValueError('在用例文件{}行缺少定义attribute_value_的值'.format(case.index(step)))
                else:
                    raise ValueError('在用例文件{}行缺少定义operate_obj_的值'.format(case.index(step)))
                pass
            else:
                raise ValueError('在用例文件{}行缺少定义save_obj_的值'.format(case.index(step)))
        if action_ == 'assert':
            assert_type_=  step.get('assert_type',None)
            assert_value_ = step.get('assert_value',None)
            expect_value_  = step.get('expect_value',None)
            if assert_value_:
                if str(assert_value_).find('$') == 0:
                    # 需要取变量
                    assert_value_ = getattr(Context, str(assert_value_).lstrip('$'))
            if str(expect_value_).find('$') == 0:
                expect_value_ = getattr(Context, str(expect_value_).lstrip('$'))
            if assert_type_ and assert_value_:
                if assert_type_ == 'assert_textin':
                    AssertUtil.assert_text_in(getattr(Context,assert_value_),expect_value_,'{}不在{}中'.format(expect_value_,assert_value_))
                if assert_type_ == 'assert_equal':
                    assert assert_value_ == expect_value_,"实际值{}与期望值{}不相等".format(assert_value_,expect_value_)
                if assert_type_ == 'assert_not_none':
                    assert assert_value_ ,'期望值{}是None'.find(assert_value_)
            else:
                raise ValueError('在用例文件{}行缺少定义assert_type_的值'.format(case.index(step)))

testcase文件:

    @pytest.mark.skip
    def test_02(self):
        #casedesc:验证搜索书籍功能
        runexcel_case(self.driver,'case01')
    @pytest.mark.skip
    def test_03(self):
        #验证书城初始页面加载的是其他类型的书籍列表
        runexcel_case(self.driver,'case02')
    def test_04(self):
        #验证加入书架功能
        runexcel_case(self.driver,'case03')

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

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

相关文章

Java8方法引用和Lambda表达式实例源码+笔记分享

前言 Java8的lambda表达式,通过lambda表达式可以替代我们之前写的匿名内部类来实现接口。lambda表达式本质是一个匿名函数。 1、lambda表达式本质是一个匿名函数。 1 package com.demo.main;2 3 public class LambdaMain {4 5 public static void main(String[…

环辛炔衍生物DBCO-NH2,amine,Acid,NHS,Maleimide无铜点击反应

DBCO对叠氮化物具有非常高的反应选择性,可用于修饰生物分子,包括肽、蛋白质、酶、活细胞、整个生物体等。在生理温度和pH值范围内,DBCO基团不与胺或羟基反应,DBCO也与叠氮化物基团发生反应DBCO也称为ADIBO(氮杂二苯并环…

2022.11.15-二分图专练

目录 50 years, 50 colors(HDU-1498) Uncle Toms Inherited Land*(HDU-1507) Matrix(HDU-2119) Arbiter(HDU-3118) [ZJOI2007]矩阵游戏(黑暗爆炸1059) Jimmy’s Assignment(HDU-1845) 50 years, 50 colors(HDU-1498) 原题链接:传送门 题意:一个n*n的矩阵中,…

第四章. Pandas进阶—数据格式化

第四章. Pandas进阶 4.1 数据格式化 1.设置小数位数(round函数) DataFrame.round(decimals0,*args,**kwargs)参数说明: decimals:用于设置保留的小数位数 args,kwargs:附加关键字的参数 返回值:返回DataFrame对象 1).示例&#…

HTML常用标签的使用

HTML常用标签的使用 文章目录HTML常用标签的使用1.排版标签1.1 标题标签(h)1.2 段落标签(p)1.3 换行标签(br)1.4 水平线标签(hr)2.文本格式化标签(strong、ins、em、del&…

Vue(七)——Vue中的Ajax

目录 Vue脚手架配置代理 插槽 默认插槽 具名插槽 作用域插槽 Vue脚手架配置代理 本案例需要下载axios库:npm install axios 1.配置类方式(实现WebMvcConfigurer) 2.使用CrossOrigin注解 3.使用nginx反向代理解决跨域 4.Vue中配置代理服务器 代理服务器怎…

懒人的法宝——办公自动化!

没错!办公自动化他来了!果然,代码都是懒人发明出来的。接下来让我们一起来看看这个批改作业的自动化脚本吧!学会了这种思想可以帮助我们高效解决许多重复性的工作,比如说批量修改文件的名称、类型、位置等等&#xff0…

【附源码】计算机毕业设计JAVA计算机系教师教研科研管理系统

项目运行 环境配置: Jdk1.8 Tomcat8.5 Mysql HBuilderX(Webstorm也行) Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。 项目技术: Springboot mybatis Maven Vue 等等组成,B/…

计算机网络-网络层(BGP协议,IP组播,IGMP协议与组播路由选择协议)

文章目录1. BGP协议BGP协议报文格式2. RIP,OSPF,BGP协议对比3. IP组播4. IGMP协议与组播路由选择协议1. BGP协议 与其他自治系统的邻站BGP发言人(BGP边界路由器)交换信息 BGP边界路由器之间交换网络可达性的信息,即要…

C++Qt开发——SMTP协议

1. SMTP协议简介 SMTP协议:全称为 Simple Mail Transfer Protocol,简单邮件传输协议。它定义了邮件客户端软件和SMTP邮件服务器之间,以及两台SMTP邮件服务器之间的通信规则。 SMTP是一个相对简单的基于文本的协议。在其之上指定了一条消息的…

网络安全之命令执行漏洞复现

0x01 漏洞介绍 漏洞等级:严重 Webmin是功能最强大的基于Web的Unix系统管理工具。管理员通过浏览器访问Webmin的各种管理功能并完成相应的管理动作。在版本1.997之前的Webmin中存在一个任意命令注入漏洞,触发该漏洞需登录Webmin。 0x02 漏洞影响范围 …

GitHub最新发布 阿里十年架构师手写版spring全家桶笔记全新开源

嗨咯,大家好! 没错,又是我,还跟前面一样,有好东西我才会出现。那是什么好东西呢?今天啊,给他分享阿里在Github最新发布的spring全家桶笔记第九版,这份笔记一共分三份:sp…

自学前端开发 - VUE 框架 (二):渲染、事件处理、表单输入绑定、生命周期、侦听器、组件基础

[TOC](自学前端开发 - VUE 框架 (二) 事件处理、表单输入绑定、生命周期、侦听器、组件基础) 事件处理 可以使用 v-on 指令 (简写为 ) 来监听 DOM 事件,并在事件触发时执行对应的 JavaScript。用法:v-on:click"methodName" 或 click"ha…

音视频进阶知识

亮度方程 亮度方程给出彩色光的亮度Y与三基色(R、G、B)的关系式Y1.0000R4.5907G0.06015B 在不同的彩色电视制式中,由于所选的标准白光和显像三基色不同,导致亮度方程也互有差异。 以C光为标准白光源的NTSC制彩色电视制式的亮度方程…

[java/初学者/GUI编程]GUI界面设计——界面组件类

前言 GUI,即图形用户界面,其英文全称是Graphics User Interface。 它是基于图形的界面,windows就是一个图形用户界面的操作系统,而DOS是基于命令提示符的操作系统,GUI编程就是编出一个图形用户界面的软件,它使用图形的方式,以菜…

昇思MindSpore时序AI SIG,共同提高序列大数据分析能力

随着信息产业技术的升级,产生了大规模的时间序列数据,长期并广泛存在于工业制造、航空航天、公共卫生、环境保护等关键基础领域。时间序列信息能够被充分理解、计算和利用,实现精准预测并辅助决策,是关系到国家竞争力的重要问题。…

Adaptive Cruise Control (ACC) Test Scenarios(PreScan里面的ACC)

文章目录Adaptive Cruise Control (ACC) Test Scenarios PreScan scenario models available with the ACC system ACC模型的几个预扫描场景可用: 真实生活场景–系统的典型用例 ISO测试协议 这些模型展示了如何使用PreScan对ADAS系统进行建模,并提供“…

Day 56 | 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇

583. 两个字符串的删除操作 解法一:直接求删除的步数 动态规划解题思路: ①确定dp数组以及下标含义 dp[i][j]:以下标i-1结尾的字符串s与下标j-1结尾的字符串t想要达到相等,所需要删除元素的最少次数。 ②确定递推公式 每次…

spring - AnnotationConfigApplicationContext启动之reader、scanner、register逻辑整理

前言 我们在使用spring framework时一般都喜欢按照以下方式写启动 AnnotationConfigApplicationContext applicationContext new AnnotationConfigApplicationContext(AppConfig.class); 而我们的AnnotationConfigApplicationContext的内容如下 public AnnotationConfigAp…

长时间预测模型DLiner、NLiner模型(论文解读)

前言 今年发布8月份发布的一篇有关长时间序列预测(SOTA)的文章,DLiner、NLine在常用9大数据集(包括ETTh1、ETTh2、ETTm1、ETTm2、Traffic等)上MSE最低,模型单变量、多变量实验数据: 在计算资…