一、介绍
uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库,仅支持Android平台的原生应用测试。。其底层基于Google uiautomator,Google提供的uiautomator库可以获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意操作。它提供便利的python接口。允许测试人员直接在PC上编写Python的测试代码,操作手机应用,完成自动化测试,大大提高自动化代码编写的效率。
原理解释:
python端:运行脚本,往移动端发送HTTP请求
移动端:安装atx-agent,然后atx-agent启动uiautomator2服务进行监听,并识别python脚本,转换为uiautomator2的代码。
移动设备通过WIFI(同一网段)或USB接收到PC上发来的HTTP请求,执行制定的操作
二、安装
安装 uiautomator2,
命令行窗口:pip install -U uiautomator2
设备安装atx-agent:
# init就是所有USB连接电脑的手机上都安装uiautomator2
python -m uiautomator2 init
三、安装weditor
在APP自动化测试是,需要使用到元素定位,UI元素定位的工具--WEditor,方便我们快速的识别手机上的元素,方便写代码。WEditor能够提供辅助编写脚本,定位元素,调试代码等功能,是基于python的一个查看APP元素的工具。
安装命令:pip install weditor==0.6.4
由于直接命令pip install weditor会报错,解决方法 太麻烦,所以直接降版本安装。
查看安装是否成功:weditor --help
使用:命令行窗口输入:python -m weditor ,默认启动后,会直接在本地打开一个网页,接下来的操作都可以只在这个网页完成。
四、操作及应用
1、链接手机
device = uiautomator2.connect() ,用的最多的是默认只有一台连接,或指定序列号链接。
import uiautomator2 as u2
#链接设备,这里是通过adb链接手机的;所以要提前装好adb;并能够adb devices发现该设备;
#用的最多的是默认的和指定序列号的,最方便
#不提供参数,默认连接方式,适用于只有一台设备
#device = u2.connect()
#有多台设备,指定设备ip,通过USB链接, 我的设备序列号是127.0.0.1
#device = u2.connect('127.0.0.1')
#通过wifi链接,设备IP要和PC在同一网络;在夜神模拟器,查到的序列号和ip同样
#device = u2.connect_wifi('127.0.0.1')
#打开被测试的app
device(text='浏览器').click()
注:用adb devices 查看当前pc链接的所有设备。
2、APP操作:安装、卸载、启动
这些操作都需要 用到app 的包名:device.app_current()
import uiautomator2 as u2
#链接设备,这里是通过adb链接手机的;所以要提前装好adb;并能够adb devices发现该设备;
#用的最多的是默认的和指定序列号的,最方便
#不提供参数,默认连接方式,适用于只有一台设备
#device = u2.connect()
#有多台设备,指定设备ip,通过USB链接, 我的设备序列号是127.0.0.1
device = u2.connect('127.0.0.1')
#通过wifi链接,设备IP要和PC在同一网络
#device = u2.connect_wifi('127.0.0.1')
#安装apk
#device.app_install("http://www.baidu.com/abc.apk")
#获取正在运行的apk的包名
pkgname = device.app_current
print(pkgname)
#卸载app,参数是包名
#device.app_uninstall(pkgname)
#启动app,传入要打开apk 的包名
device.app_start(pkgname)
#点击启动,打开被测试的app
device(text='浏览器').click()
#关闭app
device.app_stop(pkgname)
#清楚APP的数据,通常测试时不希望上次测试的动作影响下一次的测试;所以可以清除一下
device.app_clear(pkgname)
3、获取pkg_name
通过代码获取正在运行的APP包名:
#获取所有正在运行的APP包名
print(device.app_list_running())
#获取当前正在运行的APP包名
print(device.app_current())
adb指令获取:在命令行窗口输入命令
adb shell dumpsys activity | find "mFocusedActivity"
adb shell dumpsys activity top | findstr ACTIVITY
4、设备操作
获取设备信息
#以字典的形式打印设备信息
print(device.info)
# 获取窗口大小
print(device.window_size())
# 获取当前应用程序信息。对于某些android设备,输出可以为空
print(device.current_app())
# 获取设备序列号
print(device.serial)
# 获取WIFI IP
print(device.wlan_ip)
# 获取详细的设备信息
print(device.device_info)
5、截图
#截屏,两种方式,
#先截后存
image = device.screenshot()
image.save("image_path.jpg")
# 截屏并保存
device.screenshot("image_path.")
6、文件推拉
# 推送到文件夹
device.push("text.txt", "/sdcard/")
# 推送后重命名
device.push("text.txt", "/sdcard/new_name.txt")
# 推送 fileobj
with open("text.txt", 'rb') as f:
device.push(f, "/sdcard/")
# 推动和更改文件访问模式,755是Linux里的7:可读可写可执行;
device.push("text.sh", "/data/local/tmp/", mode=0o755)
#拉取文件
device.pull("/sdcard/text.txt", "text.txt")
# 如果在设备上找不到文件,FileNotFoundError将引发
device.pull("/sdcard/file_not_exists.txt", "text.txt")
7、按键操作
device.screen_on()#打开屏幕
device.screen_off() #关闭屏幕
device.press("home") # 点击home键
device.press("back") # 点击back键
device.press("left") # 点击左键
device.press("right") # 点击右键
device.press("up") # 点击上键
device.press("down") # 点击下键
device.press("center") # 点击选中
device.press("menu") # 点击menu按键
device.press("search") # 点击搜索按键
device.press("enter") # 点击enter键
device.press("delete") # 点击删除按键
device.press("recent") # 点击近期活动按键,最近浏览的APP
device.press("volume_up") # 音量+
device.press("volume_down") # 音量-
device.press("volume_mute") # 静音
device.press("camera") # 相机
device.press("power") #电源键
#更多具体查看Android keyCode
五、元素定位
UiAutomator定位用于Android APP的元素定位,使用UI Automator API(UISelector类)来搜索特定元素。Android APP页面布局用的是xml 可扩展标记语言,类似于HTML,可以粗俗的把元素定位理解为HTML的元素定位;下面是 UiSelector 类的一些常用接口使用方法。
元素定位辅助工具:weditor,UI元素定位的工具--WEditor,方便我们快速的识别手机上的元素,方便写代码。WEditor能够提供辅助编写脚本,定位元素,调试代码等功能,是基于python的一个查看APP元素的工具。weditor运行时,会在浏览器打开一个页面,这个页面辅助我们定位APP上的元素。
命令行窗框输入:weditor ,会在浏览器打开页面,手机上的内容就全部展示在浏览器上;相当于web页面打开 F12控制台一样效果。左侧,相当于手机页面,可以直接操作;中间显示元素属性,相当于F12控制台;右边显示录制脚本的代码。右下Hierarchy,点击名称,显示元素控件位置。
最上面部分,是管理手机的,例如Android、ios;例如链接那台手机;dunp Hierarchy 刷新;
weditor优势在于:一、可以同时管理多台设备;二、直接在调试界面操作手机,不需要另一只手去动手机;三、右边coding区自动生成脚本对应 python 代码。
元素构成:控件由空间名称、控件属性、子控件构成;每个控件的控件名称、属性,都可以weditor页面中间模块找到;根据名称、属性,找到对应控件,指定执行操作,名称和属性可以组合使用。
定位方式:根据weditor中间模块的 prop结构词定位;ui2支持 android 中 UiSelector 类中的所有定位方式。具体参考官方文档
名称 | 描述 |
---|---|
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为符合指定正则的元素 |
示例代码:
import uiautomator2 as u2
#导入元素定位辅助工具
import weditor
#adb连接手机
device = u2.connect('127.0.0.1')
#定位元素并操作;这些属性可以组合使用
device(text='浏览器').click()
#或者先定位,后操作
element = device(textStartsWith='浏览')
element.click()
子元素和兄弟定位
根据上下级关系进行定位;上级:页面的外层;下级:页面的内层;同级:sibling,同一级。
#子元素定位:
#查找类名为android.widget.ListView下的Bluetooth元素
device(className="android.widget.ListView").child(text="Bluetooth")
#兄弟元素定位
element = device(textContains='个人中心', className='android.widget.TextView')
#若是只有一个兄弟元素,可以不用传参
element.sibling(text='购物车').click()
相对位置定位
相对定位可以定位某个元素的前后左右元素,定位速度慢,因为要做页面渲染;不建议用。括号里面可以添加相对定位的目标元素结构词方法,不添加,则默认选择对应位置的第一个元素。
element = device(textContains='个人中心', className='android.widget.TextView')
element.left(text='评价').click() #不填参数,则默认左边第一个元素
element.right(text='购物车').click()
element.up(text='付款').click()
element.down(text='订单').click()
元素常用api:如 element.exists() ,判断 element 元素是否存在。
方法 | 描述 | 返回值 | 备注 |
---|---|---|---|
exists() | 判断元素是否存在 | True,Flase | @property装饰的类属性方法 |
info | 返回元素的所有信息 | 字典 | @property装饰的类属性方法 |
get_text() | 返回元素文本 | 字符串 | |
set_text(text) | 设置元素文本 | None | |
clear_text() | 清空元素文本 | None | |
center() | 返回元素的中心点位置 | (x,y) | 基于整个屏幕的点 |
六、APP操作:点击、拖动、滑动、长按
点击: click:
device(text='').click() ,通过元素定位;
device.click(x,y) 通过全局坐标点击,元素定位不便时使用;
滑动:device.swipe
输入:先定位元素,再输入;
输入:element.send_keys()
清空:element.clear_text()
七、智能等待
强制等待是 time.sleep(5);这个等待时间是固定的,智能等待,等待事件完成,然后开始进行下一步;主要有:
device.app_start('package_name',wait=true) ;等待APP启动完成;不需要time.sleep(),加上wait=true;
device.wait_activity()
device(text'='button').wait() 等待button元素出现
device(text='password').wait_gone() 等待password元素消失
device().exist() 等待元素是否存在
device.implicitly_wait() 设置等待超时时间,也可单独给元素设置;如device().click(tiimeout=10)。
等待点击,设置隐式等待后: click() , clear_text()
八、toast
展示及获取toast弹窗信息
#展示toast信息
device.toast.show("Hello world")
#获取toast信息
device.toast.get_message()
九、案例实战