基于Python3 + appium的Ui自动化测试框架
UiAutoTest
一、概要
数据驱动的Ui自动化框架
二、环境要求
- 框架基于Python3 + unittest + appium
- 运行电脑需配置adb、aapt的环境变量,build_tools版本建议选择28及以上
- 配置appium环境,并确保appium版本1.9及以上
- 目前只支持安卓手机,建议使用安卓7.0及以上设备
- 运行时候,电脑只能同时连接一台测试机
三、框架结构和原理
3.1 框架原理
框架结构设计分为四层,自下而上分别为:基础工具类Base层、页面操作PageObject层、测试用例集TestCase层和主程序runAll.py
框架的大致工作流程为:主程序runAll.py使用unittest的discover方法从TestCase批量添加测试用例并执行,而每一个测试用例都调用PageObject/Page.py模块下的operate/check方法来做执行/断言操作,operate/check方法首先调用Base/BaseGetParams.py模块下的get_operate_params/get_check_params方法组装来自Excel的执行/断言数据,然后再调用Base/BaseOperate.py模块下的各种操作方法完成对应的元素操作动作,其结构如下图:

3.2 各模块说明
- App - 存放待测apk
- Base - 存放基础工具类
- DrivingData - 存放测试驱动数据(excel格式)
- Log - 存放日志
- PageObject - 封装页面的操作逻辑和校验逻辑
- Result - 存放测试结果
- TestCase - 存放测试用例
- config.ini - 配置文件
- runAll.py - 主脚本
四、框架使用说明
使用该框架的流程主要有以下四步:
- 第一步,按照Excel数据格式填写驱动数据
- 第二步,在TestCase里写测试用例脚本
- 第三步,按照需求修改配置文件config.ini
- 第四步,运行主程序runAll.py
以下,为该框架详细使用说明
- Excel驱动数据 - 各字段详细说明(*表示重要字段) 
  - *step:执行步骤,可选operate和check,operate表示操作,check表示断言
- step_desc:执行步骤描述,打印日志使用
- page_object:操作步骤所处的页面描述,打印日志使用
- *location_type:常用定位方式, 可选方式为:id,xpath,name,class_name,css_selector,ids,xpaths,names,class_names,css_selectors,结尾为s的表示定位一组元素
- index:索引,如果location_type用定位一组元素,用index索引确定具体的元素,索引的下表从0开始,即要取组元素中的第一个元素,index为0
- *location_value:定位值,注意定位值里面均为英文字符,如有中文会导致无法正确定位
- *operate_method:常用操作方法,可选方法为:click,input,wait,imp_wait,close_allow_box,swipe_by_ratio,text,screenshot,quit
- *operate_value:操作值,如有多个,中间以空格隔开
- execution:运行标志位,Yes为需要执行,No不执行
 
- Excel驱动数据 - operate_method详细说明 
  - click - 点击事件,location_type、location_value为必填字段,operate_value为空
- input - 清除输入框文本并输入事件,location_type、location_value、operate_value为必填字段,其中operate_value填写输入内容
- wait - 强制等待事件,location_type、location_value为空,operate_value(非必填项)填数字,如不填默认等待时间为1s,否则按照填写时间执行
- imp_wait - 隐式等待,location_type、location_value为空,operate_value(非必填项)填数字,如不填默认等待时间为5s,否则按照填写时间执行
- close_allow_box - 关闭权限弹框事件,location_type、location_value为空,operate_value(非必填项)填写格式为:权限button内容 关闭次数,如不填默认匹配允许字符,关闭次数为1次
- swipe_by_ratio - 滑动事件,location_type、location_value为空,operate_value(非必填项)填写格式:开始坐标 方向 滑动比例 持续时间(毫秒),如不填默认start_x=500, start_y=800, direction='up', ratio=0.1, duration=200执行
- text - 获取元素文本,location_type、location_value为空,operate_value(非必填项),通常用于check方法下,获得的元素文本与operate_value内容作对比
- screenshot - 截图事件,location_type、location_value为空,operate_value(非必填项)填写内容为截图文件名,如不填默认为screenshot+当前时间戳
- quit - 退出时间,一般用于运行结束,关闭app
- is_login - 判断是否登录,如果是则退出,回到登录页,如果不是则直接进入登录页,location_type、location_value为空,operate_value(非必填项),填写内容为:登录标志字段 设置按钮的定位方式 设置按钮的定位值,如:登录 id com.aspirecn.xiaoxuntongParent.ln:id/me_setting
 - is_login方法源码 - BaseOperate.py - def is_login(self, login_text='登录', set_loc_type='id', set_loc='com.aspirecn.xiaoxuntongTeacher.ln:id/me_setting'):
 """
 判断是否为登录状态,是退出,否进入登录页
 :param login_text: 判断是否登录的标志字段
 :param set_loc_type: 设置元素定位方式
 :param set_loc: 设置元素定位
 :return:
 """
 wo_loc = "//*[@text='我']"
 login_text_loc = "//*[contains(@text, '%s')]" % login_text
 wo_el = self.find_element('xpath', wo_loc)
 self.to_click(wo_el[1]) if wo_el[0] else logger.info("切换'我'定位失败,请检查xpath是否正确:%s" % wo_loc)
 if self.find_element('xpath', login_text_loc)[0]:
 logger.info('the app is logout status')
 self.to_click(self.find_element('xpath', login_text_loc)[1])
 else:
 set_el = self.find_element(set_loc_type, set_loc)
 self.to_click(set_el[1]) if set_el[0] else logger.info("'设置'定位失败,请检查%s是否正确:%s" % (set_loc_type, wo_loc))
 logout_el = self.find_element('xpath', "//*[contains(@text, '退出')]")
 self.to_click(logout_el[1]) if logout_el[0] else logger.info("'退出'定位失败,请检查xpath是否正确:%s" % "//*[contains(@text, '退出')]")- swipe_by_ratio方法源码 - BaseOperate.py - def swipe_by_ratio(self, start_x=500, start_y=800, direction='up', ratio=0.1, duration=200):
 """
 The function of swipe by ratio(按比例滑动屏幕)
 :param start_x: start abscissa
 :param start_y: start ordinate
 :param direction: The direction of swipe, support 'up', 'down', 'left', 'right'
 :param ratio: The screen ration's distance of swiping
 :param duration: continue time, unit ms
 :return:
 """
 self.force_wait(3)
 direction_tuple = ('up', 'down', 'left', 'right')
 if direction not in direction_tuple:
 logger.info('This swiping direction is not support')
 width, height = self.get_screen_size() def swipe_up():
 """
 swipe to up
 :return:
 """
 end_y = start_y - height * ratio
 if end_y < 0:
 logger.info('the distance of swiping too much')
 else:
 self.driver.swipe(start_x, start_y, start_x, end_y, duration)
 logger.info('from (%s, %s) swiping up to (%s, %s), during %sms' % (start_x, start_y, start_x, end_y, duration)) def swipe_down():
 """
 swipe to down
 :return:
 """
 end_y = start_y + height * ratio
 if end_y > height:
 logger.info('the distance of swiping too much')
 else:
 self.driver.swipe(start_x, start_y, start_x, end_y, duration)
 logger.info('from (%s, %s) swiping down to (%s, %s), during %sms' % (start_x, start_y, start_x, end_y, duration)) def swipe_left():
 """
 swipe to left
 :return:
 """
 end_x = start_x - width * ratio
 if end_x < 0:
 logger.info('the distance of swiping too much')
 else:
 self.driver.swipe(start_x, start_y, end_x, start_y, duration)
 logger.info('from (%s, %s) swiping left to (%s, %s), during %sms' % (start_x, start_y, end_x, start_y, duration)) def swipe_right():
 """
 swipe to right
 :return:
 """
 end_x = start_x + width * ratio
 if end_x > width:
 logger.info('the distance of swiping too much')
 else:
 self.driver.swipe(start_x, start_y, end_x, start_y, duration)
 logger.info('from (%s, %s) swiping right to (%s, %s), during %sms' % (start_x, start_y, end_x, start_y, duration))
 swipe_dict = {
 'up': swipe_up,
 'down': swipe_down,
 'left': swipe_left,
 'right': swipe_right
 }
 # 【错误】,以下写法逻辑有问题,即在初始化字典时候就已经执行了所有滑动方法,最后还要返回的是swipe_dict[direction]函数
 # swipe_dict = {'up': swipe_up(),'down': swipe_down(),...}
 # return swipe_dict[direction]
 # 【正确】,字典中只初始化方向对应的函数,return返回具体的滑动函数调用
 return swipe_dict[direction]()
- 测试用例集命名格式为:test_n_xxx.py,其中n为阿拉伯数字,可用数字大小控制用例集执行的先后顺序,xxx为脚本名,如: - test_2_notice.py
- 测试用例编写格式 - 测试用例命名格式与测试用例集命名格式类似,可用数字大小控制用例集执行的先后顺序
- 每一个case需要传入不同的sheet,用于取数据
- 如果该条case无check,则不用写self.assertEqual(page.check()[0], True, msg=page.check()[1])
- 另外,在最后的setUpClass和tearDownClass方法下的super类中写当前测试用例集的类名,如:super(SendNotice, cls).setUpClass(),SendNotice为该用例集的类名
- 其余内容复制粘贴即可,详情如以下代码片段所示
 - from PageObject.Pages import PageObjects
 from Base.BaseRunner import ParametrizedTestCase class SendNotice(ParametrizedTestCase):
 """
 发通知测试
 """ def test_1_send_text(self): """发文本通知""" app = {
 'driver': self.driver,
 'data_path': self.data_path,
 'sheet': 'text_notice'
 }
 page = PageObjects(app)
 page.operate()
 self.assertEqual(page.check()[0], True, msg=page.check()[1]) def test_2_send_rich_text(self): """发图文音频通知""" app = {
 'driver': self.driver,
 'data_path': self.data_path,
 'sheet': 'rich_text_notice'
 }
 page = PageObjects(app)
 page.operate()
 self.assertEqual(page.check()[0], True, msg=page.check()[1]) @classmethod
 def setUpClass(cls):
 super(SendNotice, cls).setUpClass() @classmethod
 def tearDownClass(cls):
 super(SendNotice, cls).tearDownClass()
 
- 配置文件说明 - # --- PATH CONFIG --- #
 # 注意:以下均以使用该路径的py文件为当前路径的相对路径表达式
 [LOG_PATH]
 path = ../Log
 [RESULT_PATH]
 path = ./Result/
 # teacher
 [T_DATA_PATH]
 path = ./DrivingData/teacher.xlsx
 [T_APK_PATH]
 path = ./App/T_XXT_LN_35.apk
 [T_CASE_PATH]
 path = ./TestCase/teacher
 # parent
 [P_DATA_PATH]
 path = ./DrivingData/parent.xlsx
 [P_APK_PATH]
 path = ./App/P_XXT_LN_37.apk
 [P_CASE_PATH]
 path = ./TestCase/parent # --- OTHER FUNC CONFIG --- #
 [WAIT]
 # 显示等待时间
 time = 6 [NORESET]
 # 重置应用(清除session信息),True为不需要重置,False为需要重置
 noReset = True [PORT]
 # appium服务的端口号,默认为4723,启动时请确认appium的端口号与之一致
 port = 4723 [APP_TYPE]
 # 启动的客户端类型,若启动启动两个客户端`teacher`和`parent`中间用英文','隔开即可
 role_lst = teacher,parent
 # role_lst = teacher
 # role_lst = parent [OUTPUT]
 # 运行结果输出的方式,to_html为生成HTML测试报告,to_console为结果输出在控制器
 # method = to_html
 method = to_console
 
参考
OK
~
~
~
不积跬步,无以至千里
基于Python3 + appium的Ui自动化测试框架的更多相关文章
- 基于selenium+Python3.7+yaml+Robot Framework的UI自动化测试框架
		前端自动化测试框架 项目说明 本框架是一套基于selenium+Python3.7+yaml+Robot Framework而设计的数据驱动UI自动化测试框架,Robot Framework 作为执行 ... 
- 自动化测试中级篇——LazyAndroid UI自动化测试框架使用指南
		原文地址https://blog.csdn.net/iamhuanggua/article/details/53104345 简介 一直以来,安卓UI自动化测试都存在以下两个障碍,一是测试工具Mo ... 
- 数据驱动 vs 关键字驱动:对搭建UI自动化测试框架的探索
		UI自动化测试用例剖析 让我们先从分析一端自动化测试案例的代码开始我们的旅程.以下是我之前写的一个自动化测试的小Demo.这个Demo基于Selenium与Java.由于现在Selenium在自动化测 ... 
- 简单Web UI 自动化测试框架 pyse
		WebUI automation testing framework based on Selenium and unittest. 基于 selenium 和 unittest 的 Web UI自动 ... 
- UI自动化测试框架(项目实战)python、Selenium(日志、邮件、pageobject)
		其实百度UI自动化测试框架,会出来很多相关的信息,不过就没有找到纯项目的,无法拿来使用的:所以我最近就写了一个简单,不过可以拿来在真正项目中可以使用的测试框架. 项目的地址:https://githu ... 
- 基于Selenium+Python的web自动化测试框架
		一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ... 
- Ui自动化测试框架
		为了提高我们的UI测试效率,我们引用Ui自动化测试框架,这里简单先描述一下,后续会详细补充: 了解一个测试框架,我们就需要了解一下源码,能看懂源码即可: 1.稳定先封装wait EC,电脑性能配置较好 ... 
- UI自动化测试框架 ---TestCafe
		UI自动化测试框架 ---TestCafe 官网文档链接: https://devexpress.github.io/testcafe/ https://devexpress.github.io/te ... 
- 基于Python的HTTP接口自动化测试框架实现
		今天我们来讲一下基于Python的HTTP接口自动化测试框架的实现,范例如下: 一.测试需求描述 对服务后台一系列的http接口功能测试. 输入:根据接口描述构造不同的参数输入值 输出:XML文件 e ... 
随机推荐
- Archlinux安装与出现的问题
			arch的安装 arch的安装主要参考官网arch wiki,基本上按照Beginners' guide的步骤就可以安装,不过这里推荐用U盘刻录的方法来安装,我尝试过用硬盘安装的办法,还是感觉U盘刻录 ... 
- Nginx笔记总结七:root和alias文件路径配置
			1. root path 配置段:http.server.location.if location ~ ^/weblogs/ { root /data/weglogs/www.ttlsa.com; a ... 
- estt
			1.路由控制的定义 1.1.IP地址与路由控制 互联网是由路由器连接的网络组合而成的.为了能让数据包正确地到达目标主机,路由器必须在途中进行正确地转发.这种向"正确的方法"转发数据 ... 
- Hibernate之cascade属性和inverse属性
			1.cascade属性 cascade属性的作用是描述关联对象进行操作时的级联特性,只有涉及关系的元素才有cascade属性.具有cascade属性的标记包括<many-to-one/>. ... 
- LVS+Keepalived 配置
			LVS+Keepalived配置 环境准备 LVS1:192.168.1.1 LVS2:192.168.1.2 MySQL Server1:192.168.1.13 MySQL Server2:192 ... 
- Android 绘制中国地图
			最近的版本有这样一个需求: 有 3 个要素: 中国地图 高亮省区 中心显示数字 面对这样一个需求,该如何实现呢? 高德地图 因为项目是基于高德地图来做的,所以很自然而然的想到了高德.但是当查阅高德地图 ... 
- 自动化测试ROI实践
			自动化测试是一项"一旦开始,就需要持续投入"的工作,所以它一直是测试领域的一块鸡肋.不做吧,好像手工测试重复得让人有些厌倦,而且手工测试时间也缩短不了.做吧,害怕投入的比回报要多. ... 
- Android中Intent的各种常见作用。
			Android开发之Intent.Action 1 Intent.ACTION_MAIN String: android.intent.action.MAIN 标识Activity为一个程序的开始. ... 
- SpringBoot快速上手系列01:入门
			1.环境准备 1.1.Maven安装配置 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件. 下载Maven可执行文件 cd /usr/local ... 
- java集合-set
			#java集合-set Map用于存储key-value的映射,其中key的值是不能重复的.并且还需要正确的覆写equals方法和hashCode方法 如果我们只需要存储不重复的key,并不需要存储对 ... 
