前言
由于公司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