Uiautomator2实现Android自动化测试详解

目录

1、UIautomator2框架原理

2、UIautomator2使用

2.1、安装

2.2、元素定位工具-weditor

2.3、设备连接

2.4、全局配置

2.4.1、通过settings设置

2.4.2、通过属性设置

2.5、APP相关操作

2.5.1、安装应用

2.5.2、启动应用

2.5.3、等待应用启动

2.5.4、结束应用

2.5.5、卸载应用

2.5.6、获取当前上层APP的信息

2.5.7、获取指定APP的信息

2.6、设备相关操作

2.6.1、获取设备信息

[2.6.2、 获取屏幕分辨率](#2.6.2、 获取屏幕分辨率)

2.6.3、获取设备IP地址

2.6.4、锁屏亮屏

2.6.5、截屏

2.6.6、按键

2.6.7、输入法切换

2.6.8、录屏

2.6.9、文件的上传下载

2.8、元素定位

2.8.1、定位方法

2.8.2、支持的定位方法

[2.8.3、 组合定位](#2.8.3、 组合定位)

2.8.4、子元素定位

2.8.5、兄弟元素定位

2.8.6、多级定位

2.8.9、相对定位

2.8.10、xpath定位

2.9、元素操作

2.9.1、点击

2.9.2、长按

2.9.3、滑动

2.9.4、多点滑动

2.9.5、拖动

2.9.6、放大缩小

2.9.7、滚动

2.9.8、toast操作

2.9.9、文本相关操作

2.9.10、弹窗监测

1、UIautomator2框架原理

如上图所示,python-uiautomator2 主要分为两个部分,python 客户端,移动设备

  • python 端: 执行脚本,脚本通过封装成HTTP 请求发送到移动设备
  • 移动设备:通过 atx-agent 来接受 HTTP 请求,并将这些请求转换为 uiautomator2可识别的指令来实现自动化操作。atx-agent 充当了一个桥梁的角色。

完整流程

  1. 在移动设备上安装atx-agent(守护进程), 通过atx-agent启动 uiautomator2 服务 (默认 7912 端口) 进行监听
  2. 在 PC 上编写测试脚本并执行(相当于发送 HTTP 请求到移动设备的 server 端)
  3. 移动设备通过 WIFI 或 USB 接收到 PC 上发来的 HTTP 请求,执行指定的操作

2、UIautomator2使用

2.1、安装

pip3 install -U uiautomator2

  • 初始化环境,安装包含httprpc服务的apk到手机+atx-agent, minicap, minitouch,注:1.3.0之后的版本,执行python代码u2.connect()时会自动监测和推送这些文件。

python3 -m uiautomator2 init

  • 检查是否安装成功
    • cmd

uiautomator2 verison

  • Python

import uiautomator2 as u2

d = u2.connect() # 连接设备

print(d.info)

2.2、元素定位工具-weditor

1、安装:

  • 注意:这里指定安装0.6.4版本的,如果默认安装最新的,很可能会出现安装失败的问题,这里推荐指定安装。

pip install weditor==0.6.4

2、启动weditor

python -m weditor

3、连接Android设备

2.3、设备连接

1、默认一个设备的情况

python 复制代码
import uiautomator2 as u2
# 连接设备
d = u2.connect() 

# 当PC与设备在同一网段时,可以使用IP地址和端口号通过WIFI连接,无需连接USB线
# 默认使用端口号7912
u2.connect("10.0.0.1:7912")
u2.connect("10.0.0.1")
u2.connect("http://10.0.0.1")
u2.connect("http://10.0.0.1:7912")
等价于
u2.connect_wifi("10.0.0.1:7912")

2、多个设备时指定设备连接

python 复制代码
import uiautomator2 as u2
# 连接设备,xxx:表示指定设备的设备号,可使用命令adb devices查看
d = u2.connect("xxx") 
等价于
d = u2.connect_usb("xxx")

2.4、全局配置

2.4.1、通过settings设置

1、查看settings默认设置

python 复制代码
print(d.settings)

# 默认配置如下:
{
# 截屏失败时返回空白截屏(不抛出异常)
'fallback_to_blank_screenshot': False,
# 操作延迟,(0, 0)表示元素点击前等待0秒,点击后等待0S再执行后续操作
'operation_delay': (0, 0),
# opretion_delay生效的方法,默认为click和swipe
# 还可以设置press,send_keys,long_click等方式
'operation_delay_methods': ['click', 'swipe'],
# 元素默认等待时间(隐式等待)
'wait_timeout': 20.0,
# xpath日志
'xpath_debug': False
 }

2、通过settIng修改默认配置

python 复制代码
# 修改截图失败后的默认返回
d.settings["fallback_to_blank_screenshot"] = True
# 修改操作延迟时间
d.settings["operation_delay"] = (3, 3)
# 修改操作延迟方法
d.settings["operation_delay_methods"] = ['click', 'swipe', 'press']
# 修改默认等待时间
d.settings["wait_timeout"] = 10

# 查看是否修改成功
print(d.settings)

2.4.2、通过属性设置

1、http默认请求超时时间

python 复制代码
# 默认值60s
d.HTTP_TIMEOUT = 60 

2、等待设备在线时长

python 复制代码
# 默认20s
d.WAIT_FOR_DEVICE_TIMEOUT = 60

3、HTTP debug信息

python 复制代码
d.debug = True

2.5、APP相关操作

2.5.1、安装应用

python 复制代码
# 本地路径安装
d.app_install('tmp.apk')
# url安装
d.app_install('package_url')

2.5.2、启动应用

python 复制代码
# 如果已启动且在后台会被拉起到前台
# 如果已启动且在前台,不做任何操作,结束
# 如果未启动,则冷启动该应用
d.app_start("packageName")

# 先kill掉APP,再冷启动APP
d.app_start("packageName", stop=True)

2.5.3、等待应用启动

python 复制代码
# 等待此应用变为当前上层应用,返回pid,超时未启动成功则返回0
# front默认为false表示只要该应用在运行中就会返回pid 为true表示等待app成为当前app
d.app_wait('com.xxx', 30, front=True)

2.5.4、结束应用

python 复制代码
# 通过包名结束单个应用
d.app_stop("packageName") # 强制结束应用,但是不清除应用数据
d.app_clear('packageName') # 结束应用,并且清除应用数据

# 默认结束所有第三方应用,保留uiautomator两个依赖服务应用
# excludes参数:排除列表中的应用包名
d.app_stop_all(excludes=['com.xxx.xxx'])

2.5.5、卸载应用

python 复制代码
# 卸载成功返回true,没有此包或者卸载失败返回False
d.app_uninstall('com.xxx.xxx')

2.5.6、获取当前上层APP的信息

python 复制代码
d.app_current()

2.5.7、获取指定APP的信息

python 复制代码
d.app_info("com.XXX")

2.6、设备相关操作

2.6.1、获取设备信息

python 复制代码
# 输出设备的详细信息,报告设备号,电池,CPU信息等
d.device_info

2.6.2、 获取屏幕分辨率

python 复制代码
# 手机竖屏状态返回 (1080,2400)
# 横屏状态返回 (2400,1080)
d.window_size()

2.6.3、获取设备IP地址

python 复制代码
d.wlan_ip

2.6.4、锁屏亮屏

python 复制代码
# 锁屏
d.screen_off()
# 亮屏
d.screen_on()

2.6.5、截屏

python 复制代码
# 截图,save(fp) 传文件路径地址
d.screenshot().save("./tmp.png")

from PIL import Image

# 旋转90度截屏(逆时针旋转)
d.screenshot().transpose(Image.ROTATE_90).save("./tmp2.png")

2.6.6、按键

python 复制代码
# 按音量键"+"
d.press('volume_up')

"""
press key via name or key code. Supported key name includes:
    home, back, left, right, up, down, center, menu, search, enter,
    delete(or del), recent(recent apps), volume_up, volume_down,
    volume_mute, camera, power.
"""

2.6.7、输入法切换

python 复制代码
# 切换成uiautomator2的输入法,这里会隐藏掉系统原本的输入法,默认是使用系统输入法
# 当传入False时会使用系统默认输入法,默认为Fasle
d.set_fastinput_ime(True)

# 查看当前输入法
d.current_ime()

2.6.8、录屏

  • 需要下载依赖,官方推荐使用镜像下载

pip3 install -U "uiautomator2[image]" -i https://pypi.doubanio.com/simple

python 复制代码
# 启动录制,默认帧率为20
d.screenrecord('tmp.mp4')
# 执行其它操作
time.sleep(10)
# 停止录制,录制结束后生成视频
d.screenrecord.stop()

2.6.9、文件的上传下载

python 复制代码
# 上传文件(从电脑推送到手机) 如果是目录,这里"/sdcrad/"最后一个斜杠一定要加,否则会报错
d.push("test.txt","/sdcrad/")
d.push("test.txt","/sdcrad/test.txt")

# 下载文件(从手机推送到电脑)
d.pull('/sdcard/test.txt','text.txt')

2.7、等待

说明:等待分为强制等待和隐式等待;

  • 强制等待:不管元素是否加载,都强制等待指定时间,实际根据具体情况进行配置,只在使用的地方生效。
  • 隐式等待:在规定时间内如果元素可操作,直接进行操作;不必强制等到指定的时间;如果超过规定的时间,元素不可进行操作会抛出异常。一般会在全局配置的时候进行统一配置,配置每一步的操作都会生效。
python 复制代码
# 设置强制等待的时间为3秒,等价于:time.sleep(3)
d.sleep(3)
 
# 设置隐式等待的时间为10
d.implicitly_wait(10)

2.8、元素定位

2.8.1、定位方法

python 复制代码
d(定位方法=定位方法的值)

# 示例
#返回一个列表,当没找到元素时,返回一个空列表;存在多个元素时,返回多个列表元素
elements = d(text='Setting')
elements[0].click()
#获取元素个数
print(elements.count)

2.8.2、支持的定位方法

|-----------------------|------------------------------|
| 定位方法 | 描述 |
| text | text是指定文本的元素 |
| textContains | text中包含有指定文本的元素 |
| textMatches | text符合指定正则的元素 |
| textStartsWith | text以指定文本开头的元素 |
| className | className是指定类名的元素 |
| classNameMatches | className类名符合指定正则的元素 |
| description | description是指定文本的元素 |
| descriptionContains | description中包含有指定文本的元素 |
| descriptionMatches | description符合指定正则的元素 |
| descriptionStartsWith | description以指定文本开头的元素 |
| checkable | 可检查的元素,参数为True,False |
| checked | 已选中的元素,通常用于复选框,参数为True,False |
| clickable | 可点击的元素,参数为True,False |
| longClickable | 可长按的元素,参数为True,False |
| scrollable | 可滚动的元素,参数为True,False |
| enabled | 已激活的元素,参数为True,False |
| focusable | 可聚焦的元素,参数为True,False |
| focused | 获得了焦点的元素,参数为True,False |
| selected | 当前选中的元素,参数为True,False |
| packageName | packageName为指定包名的元素 |
| packageNameMatches | packageName为符合正则的元素 |
| resourceId | resourceId为指定内容的元素 |
| resourceIdMatches | resourceId为符合指定正则的元素 |

2.8.3、 组合定位

  • 通过不同属性的组合来完成最终元素的定位,注意:该方式定位一定是同一个层级的,如果是不同层级的则会定位失败。
python 复制代码
d(className="xxx",  text="xxx")

2.8.4、子元素定位

  • 该方式定义一定是父子层级的关系才能成功定位,不然会定位失败。
python 复制代码
d(className="xxx").child(text="xxx")

2.8.5、兄弟元素定位

  • 注意:返回结果包含元素自己本身
python 复制代码
d(text="xxx").sibling(className="android.widget.TextView")

2.8.6、多级定位

python 复制代码
d(className="xxx", resourceId="xxx").child_by_text("xxx").child(className="xxxx")

2.8.9、相对定位

python 复制代码
d(A).left(B),# 选择A左边的B
d(A).right(B),# 选择A右边的B
d(A).up(B), #选择A上边的B
d(A).down(B),# 选择A下边的B
# 示例
d(text='xxx').right(className="android.widget.TextView")

2.8.10、xpath定位

  • 注意事项:
    • Java uiautoamtor默认是不支持xpath,这是属于uiautoamtor2的扩展功能,速度会比其它定位方式慢
    • 在xpath定位中,uiautoamtor2中的description 定位需要替换为content-desc,resourceId 需要替换为resource-id
python 复制代码
# 如果找不到元素,则会报XPathElementNotFoundError错误
# 如果找到多个元素,默认返回第1个
d.xpath('//*[@content-desc="xxx"]')

# 如果想要返回的元素有多个,使用all()方法返回列表
# 使用all方法,当未找到元素时,不会报错,会返回一个空列表
d.xpath('//*[@resource-id="xxx"]').all()

2.9、元素操作

2.9.1、点击

python 复制代码
d(text='xxx').click()
#单击直到元素消失,超时时间5,点击间隔1
d(text='xxx').click_gone(maxretry=5, interval=1.0)

2.9.2、长按

python 复制代码
d(text='xxx').long_click()

2.9.3、滑动

python 复制代码
# 根据坐标滑动从(x1,y1)滑动到(x2,y2)
d.swipe(x1,y1,x1,y2)

# 滑动的扩展方法,支持上下左右的滑动
# "left", "right", "up", "down"
d.swipe_ext("up")

2.9.4、多点滑动

  • 可用来实现图案解锁
python 复制代码
# 按下不放手
touch.down(x,y)
# 停住1S
touch.sleep(1)
# 移动
touch.move(x,y)
# 放开
touch.up(x,y)
#实现长按,同一个点按下休眠10S后抬起
d.touch.down(x1,y1).sleep(10).up(x1,y1)
# 实现多点之间的移动
d.touch.down(x1,y1).move(x2,y2).move(x3,y3).up(x3,y3)

2.9.5、拖动

python 复制代码
# 在0.5s内将设置拖动至QQ上,拖动元素的中心位置
# duration默认为0.5,实际拖动的时间会比设置的要高
d(description="设置").drag_to(text="QQ", duration=0.5)

# 拖动设置到屏幕的(500, 500)位置上
d(text="设置").drag_to(500,500, duration=0.5)

# 从点(x1,y1)拖动到点(x2,y2)
d.drag(x1,y1,x2,y2)

2.9.6、放大缩小

python 复制代码
# 根据坐标进行放大和缩小
d(className="android.widget.FrameLayout").gesture(start1,start2,end1,end2)

#  缩小
d(className="android.widget.FrameLayout").pinch_in(50, 50)
# 放大
d(className="android.widget.FrameLayout").pinch_out(10, 10)

2.9.7、滚动

  • 说明:
    • 设置scrollable属性为True
    • 滚动类型:horiz 为水平 vert 为垂直
    • 所有方法均返回Bool值
    • 滚动方向:forward 向前 、backward 向后 、toBeginning 滚动至开始 、toEnd 滚动至最后 、to 滚动直接某个元素出现
python 复制代码
# 垂直滚动到页面顶部/横向滚动到最左侧
d(scrollable=True).scroll.toBeginning()
d(scrollable=True).scroll.horiz.toBeginning()
# 垂直滚动到页面最底部/横向滚动到最右侧
d(scrollable=True).scroll.toEnd()
d(scrollable=True).scroll.horiz.toEnd()
# 垂直向后滚动到指定位置/横向向右滚动到指定位置
d(scrollable=True).scroll.to(text="指定位置")
d(scrollable=True).scroll.horiz.to(text="指定位置")
# 垂直向前滚动(横向同理)
d(scrollable=True).scroll.forward()
# 垂直向前滚动到指定位置(横向同理)
d(scrollable=True).scroll.forward.to(text="指定位置")

2.9.8、toast操作

python 复制代码
# 获取toast,当没有找到toast消息时,返回default内容
d.toast.get_message(timout=3, default='no toast')
# 清空toast缓存
d.toast.reset()

2.9.9、文本相关操作

python 复制代码
# 获取元素文本
d(text="xxx").get_text()

# 设置元素文本
d(text="xxx").set_text()

# 清除元素文本
d(text="xxx").clear_text()

2.9.10、弹窗监测

  • 使用wather进行页面监测,可以用来实现弹框的监测处理
  • 当启动wather时,会新建一个线程进行监控 ,可以添加多个watcher
python 复制代码
# 注册监控,当页面内出现有OK时,点击OK
d.watcher.when('OK').click()

# 移除 allow 的监控
d.watcher.remove("allow")

# 移除所有的监控
d.watcher.remove()

# 开始后台监控
d.watcher.start()
d.watcher.start(2.0) # 默认监控间隔2.0s

# 强制运行所有监控
d.watcher.run()

# 停止监控
d.watcher.stop()

# 停止并移除所有的监控,常用于初始化
d.watcher.reset()
相关推荐
服装学院的IT男2 小时前
【Android 13源码分析】Activity生命周期之onCreate,onStart,onResume-2
android
Arms2062 小时前
android 全面屏最底部栏沉浸式
android
belldeep2 小时前
python:reportlab 将多个图片合并成一个PDF文件
python·pdf·reportlab
服装学院的IT男2 小时前
【Android 源码分析】Activity生命周期之onStop-1
android
ChinaDragonDreamer5 小时前
Kotlin:2.0.20 的新特性
android·开发语言·kotlin
FreakStudio5 小时前
全网最适合入门的面向对象编程教程:56 Python字符串与序列化-正则表达式和re模块应用
python·单片机·嵌入式·面向对象·电子diy
丶21365 小时前
【CUDA】【PyTorch】安装 PyTorch 与 CUDA 11.7 的详细步骤
人工智能·pytorch·python
_.Switch6 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一个闪现必杀技6 小时前
Python入门--函数
开发语言·python·青少年编程·pycharm
小鹿( ﹡ˆoˆ﹡ )7 小时前
探索IP协议的神秘面纱:Python中的网络通信
python·tcp/ip·php