APP自动化针对PO模式进行二次封装之basepage
APP自动化跟WEB自动化所使用的框架基本一样,都是采用的PO模式结合pytest框架编写自动化测试脚本,为了提高代码的复用性、稳定性和易维护性,我们针对PO模式进行了二次封装,将日志,等待以及异常截图加入到其中,app相比较web而言,没有鼠标 、下拉框选择、frame切换、窗口切换和上传等操作,但它有属于自己的滑屏、toast获取、上下文切换、应用切换等操作。
import time
from datetime import datetime
import allure
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from appium.webdriver.common.mobileby import MobileBy
from appium.webdriver.webdriver import WebDriver
from Common.handle_logger import case_logger
from Common.constants import OUTPUTS_DIR class BasePage:
'''
BasePage类,针对PageObjects类的二次封装
''' def __init__(self, driver: WebDriver):
self.driver = driver def wait_element_to_be_visible(self, loc, img_doc, timeout=20, frequency=0.5):
'''
等待元素可见
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("开始等待页面元素<{}>是否可见!".format(loc))
start_time = time.time()
WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
except Exception as e:
case_logger.error("页面元素<{}>等待可见失败!".format(loc))
self.save_screenshot(img_doc)
raise e
else:
end_time = time.time()
case_logger.info("页面元素<{}>等待可见,等待时间:{}秒".format(loc, round(end_time - start_time, 2))) def wait_element_to_be_click(self, loc, img_doc, timeout=20, frequency=0.5):
'''
等待元素可点击
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("开始等待页面元素<{}>是否可点击!".format(loc))
start_time = time.time()
WebDriverWait(self.driver, timeout, frequency).until(EC.element_to_be_clickable(loc))
except Exception as e:
case_logger.error("页面元素<{}>等待可点击失败!".format(loc))
self.save_screenshot(img_doc)
raise e
else:
end_time = time.time()
case_logger.info("页面元素<{}>等待可点击,等待时间:{}秒".format(loc, round(end_time - start_time, 2))) def wait_element_to_be_exist(self, loc, img_doc, timeout=20, frequency=0.5):
'''
等待元素存在
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("开始等待页面元素<{}>是否存在!".format(loc))
start_time = time.time()
WebDriverWait(self.driver, timeout, frequency).until(EC.presence_of_element_located(loc))
except Exception as e:
case_logger.error("页面元素<{}>等待存在失败!".format(loc))
self.save_screenshot(img_doc)
raise e
else:
end_time = time.time()
case_logger.info("页面元素<{}>等待存在,等待时间:{}秒".format(loc, round(end_time - start_time, 2))) def save_screenshot(self, img_doc):
'''
页面截屏保存截图
:param img_doc: 截图说明
:return:
'''
file_name = OUTPUTS_DIR + "\\{}_{}.png".format(datetime.strftime(datetime.now(), "%Y%m%d%H%M%S"), img_doc)
self.driver.save_screenshot(file_name)
with open(file_name, mode='rb') as f:
file = f.read()
allure.attach(file, img_doc, allure.attachment_type.PNG)
case_logger.info("页面截图文件保存在:{}".format(file_name)) def get_element(self, loc, img_doc):
'''
获取页面中的元素
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:return: WebElement对象
'''
case_logger.info("在{}中查找元素<{}>".format(img_doc, loc))
try:
ele = self.driver.find_element(*loc)
except Exception as e:
case_logger.error("在{}中查找元素<{}>失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e
else:
return ele def get_elements(self, loc, img_doc):
'''
获取页面中的所有元素
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:return: WebElement对象
'''
case_logger.info("在{}中查找所有元素<{}>".format(img_doc, loc))
try:
ele = self.driver.find_elements(*loc)
except Exception as e:
case_logger.error("在{}中查找所有元素<{}>失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e
else:
return ele def input_text(self, text, loc, img_doc, timeout=20, frequency=0.5):
'''
对输入框输入文本内容
:param text: 输入的文本内容
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("在{}中输入元素<{}>的内容为{}".format(img_doc, loc, text))
self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
self.get_element(loc, img_doc).send_keys(text)
except Exception as e:
case_logger.error("在元素<{}>中输入内容{}失败!".format(loc, text))
self.save_screenshot(img_doc)
raise e def clear_text(self, loc, img_doc, timeout=20, frequency=0.5):
'''
清除文本框的内容
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("在{}中清除元素<{}>的文本内容".format(img_doc, loc))
self.wait_element_to_be_click(loc, img_doc, timeout, frequency)
self.get_element(loc, img_doc).clear()
except Exception as e:
case_logger.error("在{}中清除元素<{}>的文本内容失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e def click_button(self, loc, img_doc, timeout=20, frequency=0.5):
'''
点击按钮
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("在{}中点击元素<{}>".format(img_doc, loc))
self.wait_element_to_be_click(loc, img_doc, timeout, frequency)
self.get_element(loc, img_doc).click()
except Exception as e:
case_logger.error("在{}中点击元素<{}>失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e def get_element_text(self, loc, img_doc, timeout=20, frequency=0.5):
'''
获取WebElement对象的文本值
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return: WebElement对象的文本值
'''
try:
case_logger.info("在{}中获取元素<{}>的文本值".format(img_doc, loc))
self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
text = self.get_element(loc, img_doc).text
except Exception as e:
case_logger.error("在{}中获取元素<{}>的文本值失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e
else:
case_logger.info("获取到的元素文本值为:{}".format(text))
return text def get_elements_text(self, loc, img_doc, timeout=20, frequency=0.5):
'''
获取WebElement对象的所有文本值
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return: WebElement对象的文本值的列表
'''
try:
case_logger.info("在{}中获取元素<{}>的所有文本值".format(img_doc, loc))
self.wait_element_to_be_visible(loc, img_doc, timeout, frequency)
all_text = self.get_elements(loc, img_doc)
text_list = []
for one_text in all_text:
text_list.append(one_text.text)
except Exception as e:
case_logger.error("在{}中获取元素<{}>的所有文本值失败!".format(img_doc, loc))
self.save_screenshot(img_doc)
raise e
else:
case_logger.info("获取到的元素文本值列表为:{}".format(text_list))
return text_list def get_element_attr(self, attr_name, loc, img_doc, timeout=20, frequency=0.5):
'''
获取WebElement对象的属性值
:param attr_name: 属性名称
:param loc: 元素定位的XPATH元组表达式
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return: WebElement对象的属性值
'''
try:
case_logger.info("在{}中获取元素<{}>的属性{}的值".format(img_doc, loc, attr_name))
self.wait_element_to_be_exist(loc, img_doc, timeout, frequency)
value = self.get_element(loc, img_doc).get_attribute(attr_name)
except Exception as e:
case_logger.error("在{}中获取元素<{}>的属性{}的值失败!".format(img_doc, loc, attr_name))
self.save_screenshot(img_doc)
raise e
else:
case_logger.info("获取到的元素属性{}的值为{}".format(attr_name, value))
return value def sliding_screen(self, direction, img_doc):
'''
滑屏操作
:param direction: 滑屏方向:上-up;下-down;左-left;右-right
:param img_doc: 截图说明
:return:
'''
size = self.driver.get_window_size()
try:
case_logger.info("开始向{}方向滑动".format(direction))
if direction.lower() == 'up':
self.driver.swipe(start_x=size['width'] * 0.5,
start_y=size['height'] * 0.9,
end_x=size['width'] * 0.5,
end_y=size['height'] * 0.1,
duration=200)
elif direction.lower() == 'down':
self.driver.swipe(start_x=size['width'] * 0.5,
start_y=size['height'] * 0.1,
end_x=size['width'] * 0.5,
end_y=size['height'] * 0.9,
duration=200)
elif direction.lower() == 'left':
self.driver.swipe(start_x=size['width'] * 0.9,
start_y=size['height'] * 0.5,
end_x=size['width'] * 0.1,
end_y=size['height'] * 0.5,
duration=200)
elif direction.lower() == 'right':
self.driver.swipe(start_x=size['width'] * 0.1,
start_y=size['height'] * 0.5,
end_x=size['width'] * 0.9,
end_y=size['height'] * 0.5,
duration=200)
else:
case_logger.error("方向选择错误!")
except Exception as e:
case_logger.error("向{}方向滑动屏幕失败!".format(direction))
self.save_screenshot(img_doc)
raise e def get_toast_msg(self, partial_text, img_doc):
'''
获取toast文本信息
:param partial_text: 不完整文本
:param img_doc: 截图说明
:return: toast文本
'''
loc = (MobileBy.XPATH, '//*[contains(@text,"{}")]'.format(partial_text))
try:
WebDriverWait(self.driver, 10, 0.01).until(EC.presence_of_element_located(loc))
msg = self.driver.find_element(*loc).text
print("toast出现了!!!")
return msg
except Exception as e:
print("好可惜,toast没找到!!")
case_logger.error("获取toast文本失败!")
self.save_screenshot(img_doc)
raise e def switch_to_webview(self, loc, img_doc, timeout=20, frequency=0.5):
'''
切换到webview页面
:param loc: webview页面的元素
:param img_doc: 截图说明
:param timeout: 等待的超时时间
:param frequency: 轮询频率
:return:
'''
try:
case_logger.info("等待元素{}可见,并进行webview切换".format(loc))
start_time = time.time()
WebDriverWait(self.driver, timeout, frequency).until(EC.visibility_of_element_located(loc))
cons = self.driver.contexts
case_logger.info("开始切换到webview:{}".format(cons[-1]))
self.driver.switch_to.context(cons[-1])
except Exception as e:
case_logger.error("切换webview失败!")
self.save_screenshot(img_doc)
raise e
else:
end_time = time.time()
case_logger.info("切换到webview:{}成功,等待时间:{}秒".format(cons[-1], round(end_time - start_time, 2))) def switch_to_native_app(self, img_doc):
'''
切换到app原生页面
:param img_doc: 截图说明
:return:
'''
try:
case_logger.info("切换到app原生页面")
self.driver.switch_to.context('NATIVE_APP')
except Exception as e:
case_logger.error("切换到app原生页面失败!")
self.save_screenshot(img_doc)
raise e def application_switching(self, package_name, activity_name, img_doc):
'''
应用切换
:param package_name: 包名
:param activity_name: 欢迎页面名
:param img_doc: 截图说明
:return:
'''
try:
case_logger.info("切换应用到{}".format(package_name))
self.driver.start_activity(app_package=package_name, app_activity=activity_name)
except Exception as e:
case_logger.error("切换应用到{}失败!".format(package_name))
self.save_screenshot(img_doc)
raise e
APP自动化针对PO模式进行二次封装之basepage的更多相关文章
- web自动化针对PO模式进行二次封装之basepage
在PO模式当中,我们做到了页面对象与测试用例的分离,但在页面对象编写时,我们仍然还有优化的空间.页面对象有一些共同的基本操作,可以封装起来,并可以在基本操作当中加上日志和异常截图的处理.比如说我们在查 ...
- 自动化测试po模式是什么?自动化测试po分层如何实现?-附详细源码
一.什么是PO模式 全称:page object model 简称:POM/PO PO模式最核心的思想是分层,实现松耦合!实现脚本重复使用,实现脚本易维护性! 主要分三层: 1.基础层BaseP ...
- PO模式学习笔记
框架: 1.PO模式应用(测试对象和测试用例分离)(写到简历中) 2.引入ddt 3.深入分层:测试数据分离 4.遵循原则:测试用例的独立性 5.深入分层:元素定位分离 6.框架优化:提取basepa ...
- 【基于Puppeteer前端自动化框架】【二】PO模式,断言(如何更简便逻辑的写测试代码)
一.概要 前面介绍了Puppeteer+jest+TypeScript做UI自动化,但是这知识基础的,我们实现自动化要考虑的很多,比如PO模式,比如配置文件,比如断言等等.下面就来一一实现我是怎么用p ...
- 说说UI自动化中的PO模式
PO模式,全称PageObject模式,即页面对象模式.将页面定位与业务操作分离. po模式有以下几个优点: 1.易读性好 2.扩展性高 3.复用性强 4.维护性好 5.代码冗余率低 了解了po模式及 ...
- 【Selenium07篇】python+selenium实现Web自动化:PO模型,PageObject模式!
一.前言 最近问我自动化的人确实有点多,个人突发奇想:想从0开始讲解python+selenium实现Web自动化测试,请关注博客持续更新! 这是python+selenium实现Web自动化第七篇博 ...
- Python+Selenium+Unittest实现PO模式web自动化框架(1)
1.什么是PO模式? PO是Page Object的缩写 PO模式是自动化测试项目开发实践的最佳设计模式之一,讲页面定位和业务操作分开,也就是把对象的定位和测试脚本分开,从而提供可维护性. 主要有以下 ...
- selenium(12)-web UI自动化项目实战(PO模式,代码封装)
web UI自动化项目实战-项目 项目使用禅道,所以你需要搭建1个禅道,搭建禅道的方法和步骤见 https://www.cnblogs.com/xinhua19/p/13151296.html 搭建U ...
- App 自动化框架设计思路
最近在整理和学习Appium+Java 自动化框架,对APP自动化框架的部分设想参考了一些文章,先进行整理下: 框架的思路一: 思考引入:https://www.cnblogs.com/yunfeio ...
随机推荐
- 双重检查锁单例模式为什么要用volatile关键字?
前言 从Java内存模型出发,结合并发编程中的原子性.可见性.有序性三个角度分析volatile所起的作用,并从汇编角度大致说了volatile的原理,说明了该关键字的应用场景:在这补充一点,分析下v ...
- CCF-CSP题解 201512-4 送货
求字典序最小欧拉路. 似乎不能用\(Fluery\)算法(\(O(E^2)\)).\(Fluery\)算法的思路是:延申的边尽可能不是除去已走过边的图的桥(割).每走一步都要判断是否是割,应当会超时. ...
- Python之如何修改运行的快捷键
如果你在Pycharm中运行程序使用Ctrl+shift+F10快捷键,运行失败,使用Pycharm工具组,右键一下选择“Run+文件名称AAA”运行程序,直接运行成功的话,那么你就可以 更换自己的运 ...
- cannot resolve symbol AppCompatActivity
记一次配置性的问题 今天复习自定义控件的时候新建一个project,生成的代码冒红,可把我给郁闷了.我知道我的配置是正确的,可是... 它出现了cannot resolve symbol AppCom ...
- 花生日记_花生日记APP下载_花生日记官方网站
花生日记 国内领先的社交电商导购分享平台. 独创社交电商3+模式,社交+电商+社群,上线1个月注册用户超百万.合作商家涵括各个类目以及平台.为数万宝妈提供月收入3000以上兼职收入. 微信扫描下方二维 ...
- 数据结构学习--单链表(python)
概念 链表(linked_list)是物理存储单元上非连续的.非顺序的存储结构,数据元素的逻辑顺序 是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间) ,另一个是指向 ...
- gorm操练记录
这个数据库的定义蛮全的,先作个记录. package main import ( "time" "github.com/jinzhu/gorm" _ " ...
- Android组件体系之视图绘制
一.View组件View组件有几个重要的方法需要关注,也是自定义View经常需要重写的方法. 1.measure作用是测量View组件的尺寸.对应的方法是onMeasure,测量View的宽和高.Vi ...
- Jmeter自动化集成工具Ant的安装
一.Ant介绍 Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动化的一个工具,大多用于Java环境中的软件开发.由Apache软件基金会所提供.只要使用过Linux系统的读者 ...
- Linux 周期任务
一次性任务 在某个特定的时间,执行一次后被清除 相关命令/进程 at 命令 atd进程 在centos6中,系统服务的名称: /etc/init.d/atd 查看系统上该进程时候启动: [root@e ...