python + appium 常用公共方法封装
appium 程序下载安装见之前的帖子:https://www.cnblogs.com/gancuimian/p/16536322.html
appium 环境搭建见之前的帖子:https://www.cnblogs.com/gancuimian/p/16557576.html
uiautomator2 常用公共方法封装见之前的帖子:https://www.cnblogs.com/gancuimian/p/16948536.html
selenium 常用公共方法封装见之前的帖子:
在写(UI)自动化测试用例的时候,最常用的就是方法的调用。我们在这里,把公共方法封装到一个文件中,
这样以后需要使用,直接调用这个方法就可以了。
以下为个人常使用到的一些 appium 公共方法的封装。
里面有一些操作是有重复的,这个根据个人情况,如果不需要可以不用。重复的话就多个选择,想用哪个用哪个。
包括个别的方法引用的库/类是 python 2.0版本以上弃用的,不过没关系,照样能用。
首先需要导入/引用到的库
import os,time,re,random,faker
from loguru import logger
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from typing import Dict, NoReturn, Tuple, List, Union
from appium.webdriver.webelement import WebElement as MobileWebElement
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.actions.pointer_input import PointerInput
from selenium.webdriver.support import expected_conditions
直接上代码:
class App_Page:
def __init__(self,driver):
self.driver = driver def click(self,element):
""" 根据元素点击 """
el = self.driver.find_element(*element)
el.click() def click_long(self,element,duration: int = 1000):
""" 根据元素长按1 """
el = self.driver.find_element(*element)
TouchAction(self.driver).long_press(el,duration=duration).release().perform() def new_click_long(self,element):
""" 根据元素长按2 """
el = self.driver.find_element(*element)
ActionChains(self.driver).click_and_hold(el).perform() def click_tap(self,x,y):
""" 根据坐标点击 """
action = TouchAction(self.driver)
action.tap(x=x,y=y).perform() def click_tap_long(self,x,y,duration: int = 1000):
""" 根据坐标(长按用百分比貌似不行)长按 """
action = TouchAction(self.driver)
action.long_press(x=x,y=y,duration=duration).release().perform() def click_two(self, element, sleepTime=0):
""" 点击,与第一种没太大区别,作为备用 """
if str(element).startswith("com"): # 若开头是com则使用ID定位
self.driver.find_element(*element).click() # 点击定位元素
elif re.findall("//", str(element)): # 若//开头则使用正则表达式匹配后用xpath定位
self.driver.find_element(*element).click() # 点击定位元素
else: # 若以上两种情况都不是,则使用描述定位
self.driver.find_element(*element).click() # 点击定位元素
time.sleep(sleepTime) def pinch_extend(self,kind: str = "out or in"):
""" 放大/缩小,主要用于图片操作 """
action = ActionChains(self.driver)
action.w3c_actions.devices = []
finger1 = action.w3c_actions.add_pointer_input('touch','finger1')
finger2 = action.w3c_actions.add_pointer_input('touch','finger2')
# 获取屏幕尺寸(宽高)
width = self.driver.get_window_size()['width']
height = self.driver.get_window_size()['height']
if kind == "out":
# 两个手指移动到屏幕正中间
finger1.create_pointer_move(x = width * 0.5, y = height * 0.5)
finger2.create_pointer_move(x = width * 0.5, y = height * 0.5)
# 两个手指按下去
finger1.create_pointer_down()
finger2.create_pointer_down()
# 两个手指移动
finger1.create_pointer_move(x = width * 0.5, y = height * 0.6)
finger2.create_pointer_move(x = width * 0.5, y = height * 0.4)
# 两个手指松开
finger1.create_pointer_up(0)
finger2.create_pointer_up(0)
action.perform()
elif kind == "in":
# 两个手指移动到屏幕正中间
finger1.create_pointer_move(x=width * 0.5, y=height * 0.6)
finger2.create_pointer_move(x=width * 0.5, y=height * 0.4)
# 两个手指按下去
finger1.create_pointer_down()
finger2.create_pointer_down()
# 两个手指移动
finger1.create_pointer_move(x=width * 0.5, y=height * 0.5)
finger2.create_pointer_move(x=width * 0.5, y=height * 0.5)
# 两个手指松开
finger1.create_pointer_up(0)
finger2.create_pointer_up(0)
action.perform()
else:
raise Exception("输入kind不能是非in/out") def click_press_move_one(self,x1,y1,x2,y2):
""" 按下之后滑动,长按滑动(这个用法好像不行,有用成功的踢我一脚) """
action = TouchAction(self.driver)
# 按住点(x1, y1),等待1000ms,滑动至点(x2, y2),释放
action.long_press(x=x1,y=y1).wait(500).move_to(x=x2,y=y2).release()
# 执行操作
action.perform() def click_press_move_two(self,x1,y1,x2,y2):
""" 按下之后滑动,(这里是把长按与滑动组合起来了,2步而不是1步) """
action = TouchAction(self.driver)
# 按住(x1, y1),等待xx秒,滑动至点(x2, y2),释放
action.long_press(x=x1,y=y1)
time.sleep(0.5)
# action.release() # 释放
action.perform() # 执行操作
self.driver.swipe(x1,y1,x2,y2)
action.release() # 释放 def input(self,element,value):
""" 输入框当中输入内容 """
el = self.driver.find_element(*element) # 先找到/定位到输入框
el.send_keys(value) # 输入框输入内容 def clear(self, element):
""" 清空输入框中的内容 """
el = self.driver.find_element(*element)
el.clear() def get_toast_text(self):
""" toast弹窗/获取toast文本内容 """
toast = self.driver.find_element("xpath", "//android.widget.Toast")
return toast.text def get_element_text(self,element):
""" 元素定位,获取text文本 """
el = self.driver.find_element(*element)
return el.text def get_screen_size(self) -> Tuple[int, int]:
""" 获取手机屏幕大小 """
x = self.driver.get_window_size()['width'] # 获取app的宽度
y = self.driver.get_window_size()['height'] # 获取app的高度
return x, y def swipe_screen(self, direction: str, duration_ms: int = 800) -> NoReturn:
""" 屏幕滑动操作 """
location = self.get_screen_size()
if direction.lower() == "up":
x = int(location[0] * 0.5)
start_y = int(location[1] * 0.75)
end_y = int(location[1] * 0.25)
self.driver.swipe(x, start_y, x, end_y, duration_ms)
elif direction.lower() == "down":
x = int(location[0] * 0.5)
start_y = int(location[1] * 0.25)
end_y = int(location[1] * 0.75)
self.driver.swipe(x, start_y, x, end_y, duration_ms)
elif direction.lower() == "left":
start_x = int(location[0] * 0.9)
y = int(location[1] * 0.5)
end_x = int(location[0] * 0.1)
self.driver.swipe(start_x, y, end_x, y, duration_ms)
elif direction.lower() == "right":
start_x = int(location[0] * 0.1)
y = int(location[1] * 0.5)
end_x = int(location[0] * 0.9)
self.driver.swipe(start_x, y, end_x, y, duration_ms)
else:
print("请输入正确的方向") def swipe_extend(self,x1,y1,x2,y2):
""" 根据坐标滑动 """
self.driver.swipe(x1,y1,x2,y2) def is_element_exist(self, element: Tuple[str, Union[str, Dict]], wait_seconds: int = 10) -> bool:
""" 判断元素是否存在 """
by = element[0]
value = element[1] try:
if by == "id":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.ID, value)))
elif by == "name":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.NAME, value)))
elif by == "class":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.CLASS_NAME, value)))
elif by == "text":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.LINK_TEXT, value)))
elif by == "partial_text":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.PARTIAL_LINK_TEXT, value)))
elif by == "xpath":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.XPATH, value)))
elif by == "css":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.CSS_SELECTOR, value)))
elif by == "tag":
WebDriverWait(self.driver, wait_seconds, 1).until(expected_conditions.presence_of_element_located((By.TAG_NAME, value)))
else:
raise NameError("Please enter the correct targeting elements,'id','name','class','text','xpath','css'.")
except:
return False
return True def find_elements(self, element: Tuple[str, Union[str, Dict]]) -> Union[List[MobileWebElement], List]:
""" 寻找一组元素,可用来断言该元素是否存在 """
by = element[0]
value = element[1]
try:
if self.is_element_exist(element):
if by == "id":
return self.driver.find_elements(By.ID, value)
elif by == "name":
return self.driver.find_elements(By.NAME, value)
elif by == "class":
return self.driver.find_elements(By.CLASS_NAME, value)
elif by == "text":
return self.driver.find_elements(By.LINK_TEXT, value)
elif by == "partial_text":
return self.driver.find_elements(By.PARTIAL_LINK_TEXT, value)
elif by == "xpath":
return self.driver.find_elements(By.XPATH, value)
elif by == "css":
return self.driver.find_elements(By.CSS_SELECTOR, value)
elif by == "tag":
return self.driver.find_elements(By.TAG_NAME, value)
else:
raise NameError("Please enter the correct targeting elements,'id','name','class','text','xpath','css'.")
except Exception as e:
logger.error(">>>>>>>> failed to find elements: %s is %s. Error: %s" % (by, value, e)) def is_text_exist(self, text: str, wait_seconds: int = 10) -> bool:
""" 判断text是否于当前页面存在 """
for i in range(wait_seconds):
if text in self.driver.page_source:
return True
time.sleep(1)
return False def screenshot(self, name):
""" 截图(注释的部分,根据个人需求可增or减) """
# day = time.strftime('%Y-%m-%d', time.localtime(time.time()))
# fp = "..\\Result\\" + day
fp = ".\\images\\" # ".":表示上级; "..":表示上上级 tm = time.strftime('%Y-%m-%d-%H_%M', time.localtime(time.time()))
if os.path.exists(fp):
filename = fp + "\\" + tm + '_' + name + '.png'
else:
os.makedirs(fp)
filename = fp + "\\" + tm + '_' + name + '.png'
self.driver.save_screenshot(filename) def get_screen(self, path):
""" 使用该方法也可截图,路径我没配 """
self.driver.get_screenshot_as_file(path) def screenshot_physical_key(self):
""" 截图:用命令模拟安卓物理按键事件(可能需要有root权限) """
self.driver.shell("sendevent /dev/input/event0 1 114 1")
self.driver.shell("sendevent /dev/input/event0 0 0 0")
self.driver.shell("sendevent /dev/input/event0 1 116 1")
self.driver.shell("sendevent /dev/input/event0 0 0 0")
self.driver.shell("sendevent /dev/input/event0 1 116 0")
self.driver.shell("sendevent /dev/input/event0 0 0 0")
self.driver.shell("sendevent /dev/input/event0 1 114 0")
self.driver.shell("sendevent /dev/input/event0 0 0 0") def randmon_phone(self):
""" 随机生成一个手机号,或者其他想生成的数据 """
while True:
phone = "130"
for i in range(8):
num = random.randint(0, 9)
phone += str(num)
return phone def generate_phone_number(self):
""" 随机生成手机号(与上面的实现方法一致,写法用了列表推导式) """
prefix = "130"
suffix = [random.randint(0, 9) for _ in range(8)]
return f"{prefix}{''.join([str(i) for i in suffix])}" def new_mobile(self):
""" 随机生成手机号,需下载:pip install pytest_facker """
fk = faker.Faker(locale=["zh_CN"])
return fk.phone_number() def get_toast(self):
""" toast 弹窗 """
el= self.driver.find_element(By.XPATH,'//android.widget.Toast')
return el def enter(self):
""" 回车 """
self.driver.press_keycode(MobileKey.KEYCODE_ENTER) def volume_up(self):
""" 音量加 """
self.driver.press_keycode(MobileKey.KEYCODE_VOLUME_UP) def select(self):
""" 搜索 """
self.driver.press_keycode(MobileKey.KEYCODE_SEARCH) if __name__ == '__main__':
pass
最后几个虚拟按键的封装,是引用了下面这个类,如果不想引用的话,方法里面的值直接写成对应的数字即可。
class MobileKey(PointerInput):
""" 每个数字代表的含义:https://www.jianshu.com/p/f7ec856ff56f """
KEYCODE_BACK = 4
KEYCODE_CALL = 5
KEYCODE_VOLUME_UP = 24
KEYCODE_VOLUME_DOWN = 25
KEYCODE_ENTER = 66
KEYCODE_SEARCH = 84
以上就是本人 appium自动化常用到的一些公共方法的封装。
python + appium 常用公共方法封装的更多相关文章
- JS常用公共方法封装
_ooOoo_ o8888888o 88" . "88 (| -_- |) O\ = /O ____/`---'\____ .' \\| |// `. / \\||| : |||/ ...
- appium安卓自动化的 常用driver方法封装
appium安卓自动化的 常用driver方法封装 做安卓自动化的时候,很多方法写起来会造成代码冗余,把这部分封装起来 ,添加到androidUI工具类里,随时可调用 都放在这个类下面: @Compo ...
- iOS常用公共方法
iOS常用公共方法 字数2917 阅读3070 评论45 喜欢236 1. 获取磁盘总空间大小 //磁盘总空间 + (CGFloat)diskOfAllSizeMBytes{ CGFloat si ...
- iOS 常用公共方法
iOS常用公共方法 1. 获取磁盘总空间大小 //磁盘总空间 + (CGFloat)diskOfAllSizeMBytes{ CGFloat size = 0.0; NSError *error; N ...
- 常用js方法封装
常用js方法封装 var myJs = { /* * 格式化日期 * @param dt 日期对象 * @returns {string} 返回值是格式化的字符串日期 */ getDates: fun ...
- appium+python自动化24-滑动方法封装(swipe)
swipe介绍 1.查看源码语法,起点和终点四个坐标参数,duration是滑动屏幕持续的时间,时间越短速度越快.默认为None可不填,一般设置500-1000毫秒比较合适. swipe(self, ...
- appium+python自动化24-滑动方法封装(swipe)【转载】
swipe介绍 1.查看源码语法,起点和终点四个坐标参数,duration是滑动屏幕持续的时间,时间越短速度越快.默认为None可不填,一般设置500-1000毫秒比较合适. swipe(self, ...
- Python+Appium 查找 toast 方法的封装
使用场景:在操作应用时常见toast弹框,通过toast弹框信息的获取判断当前的某个操作是否成功 引用的包:from selenium.webdriver.support import expecte ...
- Python Appium 元素定位方法简单介绍
Python Appium 元素定位 常用的八种定位方法(与selenium通用) # id定位 driver.find_element_by_id() # name定位 driver.find_ ...
- python的常用魔法方法详细总结
构造和初始化 __init__我们很熟悉了,它在对象初始化的时候调用,我们一般将它理解为"构造函数". 实际上, 当我们调用x = SomeClass()的时候调用,__init_ ...
随机推荐
- Windows Terminal 中 WSL2 默认打开路径
打开Windows Terminal.鼠标点击进入设置,或者同时按ctrl和逗号.找到如下内容: { "guid": "{07b52e3e-de2c-5db4-bd2d- ...
- Win10删除此电脑默认的7个文件夹
删除方法 用记事本拷贝以下内容,改文件后缀为reg,然后点击执行. Windows Registry Editor Version 5.00 ;如需还原去除上语句前减号即可 ;取消我的电脑" ...
- 对前三次PTA作业的总结
一.前言 通过对前三次PTA作业的总结,其中蕴含着不少知识点.它让真正开始接触Java的我一点一点的渗入其中.其包含的知识点有Java代码的大体结构,例如: public class Main{ pu ...
- 为开源项目贡献代码-pycharm使用git-登录注册功能分析-判断手机号存在接口-多种方式登录接口-腾讯云短信申请
目录 为开源项目贡献代码-pycharm使用git-登录注册功能分析-判断手机号存在接口-多种方式登录接口-腾讯云短信申请 git内容大回顾 今日内容概要 今日内容详细 1 为开源项目贡献代码 2 p ...
- 一些sql查询的case
1.单列去重,输出去重后条目数量 select count(distinct(`id`)) from student; 2.根据分数段统计数据条目:利用case when selectcount(ca ...
- uml类图中的+,-,#符号的含义
描述类的属性的可见性: UML中,可见性分为4级 1.public 公用的 :用+ 前缀表示 ,该属性对所有类可见 2.protected 受保护的:用 # 前缀表示,对该类的子孙可见 3.priva ...
- Linux环境下给python项目写个启停服务
写个服务,写完后放在/lib/systemd/system路径下 update_rule.server [Unit] Description = TinyScan update rule [Servi ...
- 7.mysql索引失效
失效的七字口诀: 模型数空运最快 模:模糊查询以%开始索引失效: 型:数据类型转换 函数:函数的索引 空:索引列为空不走索引, 运:对索引列进行加减乘除会失效 最:不按聚合索引的最左匹配会 ...
- OpenLayer——模拟运动轨迹
模拟在人地图上移动,动态绘制行动轨迹的功能,附带一个跟随的气泡弹窗. <!DOCTYPE html> <html lang="en"> <head&g ...
- spring boot2 jpa分页查询百万级数据内存泄漏
分页查询百万级数据,查询处理过程中发现内存一直飙升,最终处理程序会挂掉,通过jvisualvm可以发现频繁ygc 和fgc ,另外通过 jmap -histo:live ${pid} 命令可以看到jp ...