首页 > 编程语言 >python + uiautomator2 常用公共方法封装

python + uiautomator2 常用公共方法封装

时间:2022-12-05 14:34:20浏览次数:61  
标签:封装 sleepTime python self driver element uiautomator2 click def

前言

由于公司UI自动化框架底层用的是Uiautomator2,所以我就用Uiautomator2搭了一套UI自动化框架,思路其实和Appnium一样的。

uiautomator2是一个自动化测试开源工具,仅支持android平台的自动化测试,其封装了谷歌自带的uiautomator2测试框架;

u2 现在google 官方使用的是apk的形式来实现的,有大神封装了python来实现u2的功能的使用。

具体的了解相关的功能和实现的原理可以查看开源库:github 的地址:https://github.com/openatx/uiautomator2

 

ui2 的下载安装与环境配置等,见之前写的一篇帖子:https://www.cnblogs.com/gancuimian/p/16725664.html

ui2 的常用方法使用(未封装),见之前写的一篇帖子:https://www.cnblogs.com/gancuimian/p/16947337.html

 整体框架介绍:(非固定模式,每个人的习惯不同,框架会有些出入,有些包可以是非必要)

框架搭建

ps:这里主要讲 common 包下面的公共方法类(basepage.py模块)的封装,其它包/模块不做详细介绍

先创建一个BasePage.py

  • 为什么要单独封装一个BasePage呢? 如果说以后我们不用uiautomator2这个框架了,我们只需要更改BasePage即可,不会影响到其他类的代码。

  • 另外,这个类也可以封装自己写的公用的方法,例如:重复性很高的代码,这些方法不论在哪个app里都能用的话,我们就单独拧出来封装成一个方法。

模块创建完成后,先导入需要用到的内置库或需要提前安装的第三方库。

1 import os
2 import re
3 import time
4 import random
5 from typing import Union
6 from data.Swipe_Direction import SwipeDirection
# 第6行导入的是下方的一个类;在下面代码 207 行的方法中有引用。

下面代码为本人工作中会用到的一些操作 方法的封装。

  1 class BasePage():
  2     """ 构造函数 """
  3     def __init__(self, driver):
  4         self.driver = driver
  5 
  6     def click(self, element, sleepTime=0):
  7         """ 点击 """
  8         if str(element).startswith("com"):  # 若开头是com则使用ID定位
  9             self.driver(resourceId=element).click()  # 点击定位元素
 10         elif re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
 11             self.driver.xpath(element).click()  # 点击定位元素
 12         else:  # 若以上两种情况都不是,则使用描述定位
 13             self.driver(description=element).click()  # 点击定位元素
 14         time.sleep(sleepTime)
 15 
 16     # 点击直到元素消失
 17     def click_until_gone(self, element, kind):
 18         if kind == "id":
 19             self.driver(resourceId=element).click_gone()
 20         elif kind == "class":
 21             self.driver(className=element).click_gone()
 22         elif kind == "text":
 23             self.driver(text=element).click_gone()
 24         else:  # 若以上两种情况都不是,则使用描述定位
 25             self.driver(description=element).click_gone()  # 点击定位元素
 26 
 27     # 组合定位classname和text
 28     def click_by_classname_text(self, element1, element2):
 29         self.driver(className=element1, text=element2).click()
 30 
 31     # 组合定位classname和description
 32     def click_by_classname_description(self, element1, element2):
 33         self.driver(className=element1, description=element2).click()
 34 
 35     # 组合定位text和description
 36     def click_by_text_description(self, element1, element2):
 37         self.driver(text=element1, description=element2).click()
 38 
 39 
 40 
 41     # 根据id点击(包括非com开头的id点击定位元素)
 42     def click_by_id(self, element, sleepTime=0):
 43         self.driver(resourceId=element).click()
 44         time.sleep(sleepTime)
 45 
 46     # 根据文本点击
 47     def click_by_text(self, element, sleepTime=0):
 48         self.driver(text=element).click()  # 点击定位元素
 49         time.sleep(sleepTime)
 50 
 51     # 根据百分比坐标点击
 52     def click_by_zuobiao(self, x, y, sleepTime=0):
 53         size = self.driver.window_size()
 54         self.driver.click(int(size[0] * x), int(size[1] * y))
 55         time.sleep(sleepTime)
 56 
 57     # 根据坐标点击元素
 58     def click_coord(self, x, y):
 59         self.driver.click(x, y)
 60 
 61     # 根据坐标双击元素
 62     def double_click_by_zuobiao(self, x, y, sleepTime=0):
 63         size = self.driver.window_size()
 64         self.driver.double_click(int(size[0] * x), int(size[1] * y))
 65         time.sleep(sleepTime)
 66 
 67     # 超时时间设置点击,根据文本定位,针对点击屏幕元素反应慢的元素
 68     def click_by_text_time_out(self, element, timeout=30, sleepTime=0):
 69         self.driver(text=element).click(timeout=timeout)
 70         time.sleep(sleepTime)
 71 
 72     # 长按
 73     def long_click_extend(self, element, dur=1, sleepTime=0):
 74         zhmodel = re.compile(u'[\u4e00-\u9fa5]')
 75         if str(element).startswith("com"):  # 若开头是com则使用ID定位
 76             self.driver(resourceId=element).long_click(dur)  # 点击定位元素
 77         elif re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
 78             self.driver.xpath(element).long_click()  # 点击定位元素
 79         elif zhmodel.search(str(element)):
 80             self.driver(description=element).long_click(dur)
 81         else:
 82             self.driver(className=element).long_click(dur)
 83         time.sleep(sleepTime)
 84 
 85     # 通过文本长按
 86     def long_click_by_text(self, element, sleepTime=0):
 87         self.driver(text=element).long_click()
 88         time.sleep(sleepTime)
 89 
 90     #  通过坐标长按
 91     def long_click_by_zuobiao(self, x, y, sleepTime=0,duration: float = .5):
 92         self.driver.long_click(x, y,duration)
 93         time.sleep(sleepTime)
 94 
 95     # 清空输入框中的内容
 96     def clear(self, element):
 97         if str(element).startswith("com"):  # 若开头是com则使用ID定位
 98             self.driver(resourceId=element).clear_text()  # 清除文本
 99         elif re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
100             self.driver.xpath(element).clear_text()  # 清除文本
101         else:  # 若以上两种情况都不是,则使用描述定位
102             self.driver(description=element).clear_text()  # 清除文本
103 
104     # 输入
105     def input(self, element, value, sleepTime=0):
106         if str(element).startswith("com"):  # 若开头是com则使用ID定位
107             self.driver(resourceId=element).set_text(value)  # send_keys
108         elif re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
109             self.driver.xpath(element).set_text(value)
110         else:  # 若以上两种情况都不是,则使用描述定位
111             self.driver(description=element).set_text(value)
112         time.sleep(sleepTime)
113 
114     # 不存在搜索按钮的搜索
115     def input_by_send_keys(self, element, value):
116         self.driver.set_fastinput_ime(True)  # 切换成FastInputIME输入法
117         if str(element).startswith("com"):  # 若开头是com则使用ID定位
118             self.driver(resourceId=element).send_keys(value)  # send_keys
119         elif re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
120             self.driver.xpath(element).send_text(value)
121         else:  # 若以上两种情况都不是,则使用描述定位
122             self.driver(description=element).send_keys(value)
123         self.driver.set_fastinput_ime(False)  # 切换成正常的输入法
124         self.driver.send_action("search")  # 模拟输入法的搜索
125 
126     # 查找元素
127     def find_elements(self, element, timeout=5):  # 找元素
128         is_exited = False
129         try:
130             while timeout > 0:
131                 xml = self.driver.dump_hierarchy()  # 获取网页层次结构
132                 if re.findall(element, xml):
133                     is_exited = True
134                     break
135                 else:
136                     timeout -= 1
137         except:
138             print("元素未找到!")
139         finally:
140             return is_exited
141 
142     # 断言元素是否存在, 不能判定xpath元素
143     def assert_existed(self, element):  #
144         # assert self.find_elements(element) == True, "断言失败,{}元素不存在!".format(element)
145         return self.find_elements(element) == True
146 
147     # 判断元素是否存在(比如随机弹窗等)
148     def judge_existed(self, element, type: str = "text", timeout=2):
149         if re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
150             return self.driver.xpath(element).exists == True
151         elif type == "text":
152             return self.driver(text=element).exists(timeout=timeout) == True
153         elif type == "dec":
154             return self.driver(description=element).exists(timeout=timeout) == True
155         else:
156             pass
157 
158     #  截图
159     def screenshot(self, imageName):
160         if os.path.exists(r"./images"):
161             if os.path.exists(fr"./images/{imageName}.png"):
162                 image = self.driver.screenshot()
163                 image.save(fr"./images/{imageName}_bak.png")
164             else:
165                 image = self.driver.screenshot()
166                 image.save(fr"./images/{imageName}.png")
167         else:
168             os.mkdir(r"./images")
169             image = self.driver.screenshot()
170             image.save(fr"./images/{imageName}.png")
171 
172 
173     # 拿取文本
174     def get_text_extend(self, element=None, type: str = "id"):
175 
176         if re.findall("//", str(element)):  # 若//开头则使用正则表达式匹配后用xpath定位
177             return self.driver.xpath(element).get_text()
178         elif type == "id":
179             return self.driver(resourceId=element).get_text()
180         elif type == "selected":
181             return self.driver(selected=True).get_text()
182         else:
183             pass
184 
185 
186     # 滑动  (正常屏幕滑动,向上滑动解锁,返回主界面,解锁等通用)
187     # 坐标支持数据类型:Union[int, str]
188     def swipe_extend(self, x1=0.5, y1=0.99, x2=0.5, y2=0.3, dur: Union[int, str] = 0.2,
189                      sleepTime=0, type: str = "percent"):
190         if type == "percent":
191             size = self.driver.window_size()
192             x1 = int(size[0] * x1)
193             y1 = int(size[1] * y1)
194             x2 = int(size[0] * x2)
195             y2 = int(size[1] * y2)
196             self.driver.swipe(x1, y1, x2, y2, dur)
197             time.sleep(sleepTime)
198         else:
199             self.driver.swipe(x1, y1, x2, y2, dur)
200             time.sleep(sleepTime)
201 
202     # 按下之后滑动,长按滑动
203     def long_click_swipe(self, x1, y1, x2, y2, dur=0.8, sleepTime=0):
204         self.driver.touch.down(x1, y1).sleep(dur).move(x1, y1).move(x2, y2).up(x2, y2)
205         time.sleep(sleepTime)
206 
207     # 滑动,根据方向滑动
208     def swipe_ext_extend(self, direction: Union[SwipeDirection, str] = "up", scale=0.9, sleepTime=0):
209         self.driver.swipe_ext(direction, scale=scale)
210         time.sleep(sleepTime)
211 
212     # 缩放
213     def pinch_extend(self, element, kind: str = "out or in", percent=100, steps=50):
214         """ 在元素上面,做两个手指缩放的操作,kind in 或者out,放大或者缩小"""
215         zhmodel = re.compile(u'[\u4e00-\u9fa5]')
216         if str(element).startswith("com"):
217             selector = self.driver(resourceId=element)
218         elif not zhmodel.search(str(element)):
219             selector = self.driver(className=element)
220         elif zhmodel.search(str(element)):  # 若以上两种情况都不是,则使用描述定位
221             selector = self.driver(description=element)
222 
223         if kind == "in":
224             selector.pinch_in(percent, steps)
225         elif kind == "out":
226             selector.pinch_out(percent, steps)
227         else:
228             raise Exception("输入kind不能是非in/out")
229 
230     # 关机
231     def reboot_physical_key(self):
232         self.driver.shell("sendevent /dev/input/event0 1 116 1")
233         self.driver.shell("sendevent /dev/input/event0 0 0 0")
234         time.sleep(3)
235         self.driver.shell("sendevent /dev/input/event0 1 116 0")
236         self.driver.shell("sendevent /dev/input/event0 0 0 0")
237         time.sleep(1)
238         self.click_by_text("关闭电源")
239 
240     #   截图。用命令  模拟安卓物理按键事件(需要手机有root权限)
241     def screenshot_physical_key(self):
242         self.driver.shell("sendevent /dev/input/event0 1 114 1")
243         self.driver.shell("sendevent /dev/input/event0 0 0 0")
244         self.driver.shell("sendevent /dev/input/event0 1 116 1")
245         self.driver.shell("sendevent /dev/input/event0 0 0 0")
246         self.driver.shell("sendevent /dev/input/event0 1 116 0")
247         self.driver.shell("sendevent /dev/input/event0 0 0 0")
248         self.driver.shell("sendevent /dev/input/event0 1 114 0")
249         self.driver.shell("sendevent /dev/input/event0 0 0 0")
250 
251     # 推本地文件到手机
252     def push_extend(self, root: Union[list, str], target, sleepTime=1):
253         peojectPath = "\\".join(os.path.abspath(os.path.dirname(__file__)).split("\\")[:-1])
254         if isinstance(root, list):
255             for i in root:
256                 self.driver.push(peojectPath+i, target)
257         elif isinstance(root, str):
258             self.driver.push(root, target)
259         time.sleep(sleepTime)
260 
261 
262     def randmon_phone(self):
263         """ 随机生成一个手机号,或者其他想生成的数据 """
264         while True:
265             phone = "130"
266             for i in range(8):
267                 num = random.randint(0, 9)
268                 phone += str(num)
269             return phone

 

以上为个人常用公共方法封装,但不是全部,有些场景可能未覆盖到。更多的 ui2 相关知识可自行网上学习。

随机推荐几个ui2相关的帖子,更多的ui2的相关知识自行网上搜索了解。

https://blog.csdn.net/Makasa/article/details/124358921

https://ceshiren.com/t/topic/5396

https://blog.csdn.net/weixin_43444734/article/details/124703281

标签:封装,sleepTime,python,self,driver,element,uiautomator2,click,def
From: https://www.cnblogs.com/gancuimian/p/16948536.html

相关文章

  • scrapy3在python2,python3共存下的使用
    因为安装了PYTHON2,PYTHON3,之前的SCRAPY在PYTHON2下是可以的,但在3下运行失败,关联的还是2,原来要在PYTHON3运行的时候,要用全路径:执行scrapy命令(假设......
  • python-容器类型
    容器类型1.通用操作1.1成员运算符(1)语法:数据in容器数据notin容器(2)作用:如果在指定的序列中找到值,返回bool类型。#以字符串str为例,列表l......
  • Python脚本添加参数的几种方法
    之前用python添加参数都是用的input函数,不能添加默认值也不能输入help提示。最近发现了2个更好用的库分享给大家。一、使用input库。这个使用很简单,就不过多描述了。......
  • Python 操作 Excel
    Python操作Excel目录Python操作Excel1安装pandas2pandas中操作Excel的函数2.1loc()2.1.1根据某些条件选择数据2.1.2选择一个行的范围2.1.3根据条件更新列的值......
  • Selenium4+Python3系列(九) - 上传文件及滚动条操作
    一、上传文件操作上传文件是每个做自动化测试同学都会遇到,而且可以说是面试必考的问题,标准控件我们一般用​​send_keys()​​​就能完成上传,但是我们的测试网站的上传控件......
  • python 基础--类
    文章目录​​面向对象编程--python类​​​​类特殊的系统变量​​​​`__slots__`​​​​`@property`​​​​`__str__`​​​​`__iter__`​​​​`__getitem__`​​​......
  • python要点1
    python要点12.7下安装PIP​​​https://pypi.python.org/pypi/pip#downloads​​​注意选择tar.gz包,目前最新版本为:pip-8.1.2.tar.gz(md5,pgp)......
  • python类型转换
    1.map函数,map是python内置函数,会根据提供的函数对指定的序列做映射。map()函数的格式是:map(function,iterable,...)map函数实例delsquare(x):returnx**2map(squ......
  • spring学习小结之:hibernatetemplate,过度封装?
    边学spring,突然发现之前spring与hibernate结合的方式可以更厉害地封装,那就是用hibernateTemplate了,只需要改边userdao.java如下importorg.springfr......
  • Python---for循环
    for循环:为遍历循环,迭代循环。不同于While的条件循环。理论上来讲for循环无法构建无限循环。 python-for循环语句for临时变量in待处理数据集:实例#遍历字符串for......