IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> App自动化测试工具Uiautomator2 -> 正文阅读

[开发测试]App自动化测试工具Uiautomator2

python UIAutomator2是一个可以使用Python对Android设备进行UI自动化操作的库,底层基于Google UiAutomator(Java库)。python UIAutomator2原理是在手机上使用http rpc服务将UiAutomator中的功能开放出来,然后再将这些http接口封装成Python库。本文记录一下它的使用方法。

uiautomator2安装

uiautomator2的GitHub仓库地址为:https://github.com/openatx/uiautomator2

python安装:

pip3 install -U uiautomator2

查看是否安装成功

uiautomator2 --help

对于UI元素的查看,可以使用uiautomatorviewer或者Appium inspector,uiautomatorviewer经常用不了,Appium inspector又比较麻烦,推荐一个交weditor的工具,安装简单,使用也方便,直接在浏览器上查看。这三个工具的安装和使用方法可参考这一篇文章:App控件定位

App初始化

连接设备

d = u2.connect_usb(serial) # serial:android设备序列号,通过adb devices命令获取
d = u2.connect(serial) 
d = u2.connect("10.0.0.1") # 通过无线连接设备,10.0.0.1为手机IP地址,需要保证手机和电脑可以相互ping通(连接到同一个局域网)。
d = u2.connect("10.0.0.1:7912") # adb connect 10.0.0.1:5555

设置newCommandTimeout和隐式等待

d.set_new_command_timeout(300)  # accessibility服务的最大空闲时间,超时将自动释放
d.implicitly_wait(5)  # 隐式等待,元素查找等待时间(默认20s)

安装卸载apk

d.app_install('http://some-domain.com/some.apk')
d.app_uninstall("package_name") # 卸载APK

打开、停止App

打开APP

d.app_start(appPackage) # appPackage:包名,先通过atx-agent解析apk包的mainActivity,然后调用am start -n $package/$activity启动
d.app_start(appPackage, appActivity) # 指定appPackage和appActivity,其实就是执行adb shell am start -n appPackage/.appActivity
d.app_start(appPackage, appActivity, wait = False, stop = False, use_monkey = False) # wait: 等待app启动 stop:启动app之前先停止(需要appPackage和 appActivity) use_monkey:使用monkey命令启动app(未指定appActivity时可使用此参数)

停止APP:

d.app_stop(appPackage) # 强制停止应用,相当于adb shell am force-stop <appPackage>
d.app_clear(appPackage) # 停止并清除应用数据与缓存,相当于adb shell pm clear <appPackage>
d.app_stop_all() # 强制停止所有第三方应用(除了'com.github.uiautomator' 和 'com.github.uiautomator.test')
d.app_stop_all(excludes=['com.examples.demo']) # 停止除了com.github.uiautomator 和 com.github.uiautomator.test和com.examples.demo以外的应用

获取设备应用信息

获取应用信息

>>> d.app_info("com.android.settings")
{u'packageName': u'com.android.settings', u'label': u'Param\xe8tres', u'mainActivity': u'com.android.settings.HWSettings', u'versionName': u'10.1.0.300', u'versionCode': 10010300, u'size': 132202855}

# 当前应用信息
>>> d.app_current()

获取设备信息

>>> d.info
{u'displayRotation': 0, u'displaySizeDpY': 780, u'displaySizeDpX': 360, u'screenOn': True, u'currentPackageName': u'com.android.systemui', u'productName': u'HLK-AL10', u'displayWidth': 1080, u'sdkInt': 29, u'displayHeight': 2224, u'naturalOrientation': True}
>>>

获取详细设备信息

>>> d.device_info
{u'product': None, u'udid': u'SNHVB20C18002195-d8:a4:91:4f:5c:1e-HLK-AL10', u'brand': u'HONOR', u'cpu': {u'hardware': u'Hisilicon Kirin810', u'cores': 8}, u'usingBeganAt': u'0001-01-01T00:00:00Z', u'provider': None, u'owner': None, u'display': {u'width': 1080, u'height': 2340}, u'battery': {u'status': 5, u'scale': 100, u'temperature': 340, u'level': 100, u'acPowered': False, u'usbPowered': True, u'health': 2, u'voltage': 4355, u'wirelessPowered': False, u'technology': u'Li-poly', u'present': True}, u'version': u'10', u'presenceChangedAt': u'0001-01-01T00:00:00Z', u'agentVersion': u'0.10.0', u'memory': {u'total': 5810780, u'around': u'6 GB'}, u'hwaddr': u'd8:a4:91:4f:5c:1e', u'model': u'HLK-AL10', u'arch': u'', u'serial': u'SNHVB20C18002195', u'sdk': 29}

获取分辨率:

>>> d.window_size()
(1080, 2340)

获取设备序列号

>>> d.serial
u'SNHVB20C18002195'

获取手机IP地址

>>> d.wlan_ip
u'192.168.0.191'

其它

列出所有运行中的APP:

d.app_list_running() # adb shell pm list packages

打开网页

d.open_url("https://www.baidu.com") # adb shell am start -a android.intent.action.VIEW -d https://www.baidu.com 

等待appActivity出现

>>> d.wait_activity(".HWSettings", timeout=10)
True

UI元素定位

基本选择器

通过属性值定位,支持下面的参数:

  • text, textContains, textMatches, textStartsWith
  • className, classNameMatches
  • description, descriptionContains, descriptionMatches, descriptionStartsWith
  • checkable, checked, clickable, longClickable
  • scrollable, enabled,focusable, focused, selected
  • packageName, packageNameMatches
  • resourceId, resourceIdMatches
  • index, instance
d(className="android.widget.TextView", text="行情")
d(className="android.widget.TextView", textMatches="^行.*")

相对选择器

子孙节点定位

d(resourceId="android:id/tabs").child(text="行情")
d(resourceId="android:id/tabs").child_by_text("行情")
d(resourceId="android:id/tabs").child_by_description("description")
d(resourceId="android:id/tabs").child_by_instance("instance")

兄弟节点定位

d(className="android.widget.ImageView").sibling(text="行情")

相对定位

  • d(A).left(B): A的左边元素B
  • d(A).right(B):A的右边元素B
  • d(A).up(B):A的上边元素B
  • d(A).down(B):A的下边元素B

image

d(text="雪球").right(text="行情")
d(text="交易").left(text="行情")

d(resourceId="com.xueqiu.android:id/tab_name", instance=1)

多个实例

查看和选择实例

print(d(resourceId="com.xueqiu.android:id/tab_name").count)
print(len(d(resourceId="com.xueqiu.android:id/tab_name")))
d(resourceId="com.xueqiu.android:id/tab_name")[1].click() # 点击匹配到的第二个元素

执行结果:

4
4

也可以使用instance参数选择:

d(resourceId="com.xueqiu.android:id/tab_name", instance=1) # 使用匹配到的第2个元素

XPath定位

Java uiautoamtor默认不支持xpath,xpath定位是UIAutomator2扩展的一个功能。

d.xpath('//*[@text="行情"]').wait(10.0).click()
d.xpath('//*[@text="行情"]').click()
d.xpath('//*[@text="行情"]').exists
d.xpath('//*[@text="行情"]').all()

xpath语法可参考Web自动化测试:xpath & CSS Selector定位

元素操作方法

点击

点击UI元素

ele = d(text="微信")
ele.click(timeout=None, offset=None) # timeout:单位秒,等待元素出现;offset:默认为中心 (0.5, 0.5)
ele.long_click(duration = 0.5, timeout=None) # duration:点击时间;timeout:等待元素出现

ele.click_exists(timeout=10.0)
ele.click_gone(timeout=10.0, interval=1.0) # 

点击像素坐标

d.click(x,y) # 点击像素坐标
d.double_click(x, y, duration=0.1) # 双击像素坐标
d.long_click(x, y, duration=0.5) # 长按

文本输入

文本值获取、输入与清除

d(text="行情").get_text() # 获取元素文本

d(resourceId="com.xueqiu.android:id/action_search").click() # 点击搜索
d(resourceId="com.xueqiu.android:id/search_input_text").set_text("招商银行")  # 输入文本
d(resourceId="com.xueqiu.android:id/search_input_text").clear_text()  # 清除文本输入框文本

等待wait

等待元素

d(text="Settings").wait(timeout=3.0) # 等待元素出现
d(text="Settings").wait_gone(timeout=1.0) # 等待元素消失

WatchContext

with d.watch_context() as ctx:
    ctx.when("^立即(下载|更新)").when("取消").click() # 当同时出现 (立即安装 或 立即取消)和 取消 按钮的时候,点击取消
    ctx.when("同意").click()
    ctx.when("确定").click()
    # 上面三行代码是立即执行完的,不会有什么等待
    
    ctx.wait_stable() # 开启弹窗监控,并等待界面稳定(两个弹窗检查周期内没有弹窗代表稳定)

    # 使用call函数来触发函数回调
    # call 支持两个参数,d和el,不区分参数位置,可以不传参,如果传参变量名不能写错
    # eg: 当有元素匹配仲夏之夜,点击返回按钮
    ctx.when("仲夏之夜").call(lambda d: d.press("back"))
    ctx.when("确定").call(lambda el: el.click())

Toast操作

手机页面显示toast

d.toast.show("Hello world")
d.toast.show("Hello world", 1.0) # 显示1s

获取toast

d.toast.get_message(wait_timeout=5.0, cache_timeout=10.0, "default message") 
assert "Hello world" in d.toast.get_message(5.0, default="") # 断言toast信息
d.toast.reset() # 清除toast缓存

滑动swipe

根据像素坐标滑动

d.swipe(fx, fy, tx, ty, duration = None, steps = None) # 从(fx, fy)滑到(tx, ty),1 steps大概5ms,如果设置了steps,会忽略duration参数

基于UI对象的滑动

ele = d(text="微信")
ele.swipe(direction, steps=10) # 从UI元素中心开始滑动,direction包括"left", "right", "up", "down" 4个方向。

拖动drag_to

d(text="Settings").drag_to(x, y, duration=0.5) # 从Settings UI对象拖动到(x,y)位置
d(text="Settings").drag_to(text="Clock UI", duration=0.2) # 拖动Settings UI对象到Clock UI对象,时间为200ms

手势操作

手势放大缩小

d(text="Settings").pinch_in(percent=100, steps=10) # 缩小
d(text="Settings").pinch_out() # 放大

UI元素状态和信息

判断UI元素是否存在

d(text="行情").exists
d.exists(text="行情")
d(text="行情").exists(timeout=3)

获取元素信息

$ d(text="行情").info
{'bounds': {'bottom': 1274, 'left': 255, 'right': 285, 'top': 1253}, 'childCount': 0, 'className': 'android.widget.TextView', 'contentDescription': None, 'packageName': 'com.xueqiu.android', 'resourceName': 'com.xueqiu.android:id/tab_name', 'text': '行情', 'visibleBounds': {'bottom': 1274, 'left': 255, 'right': 285, 'top': 1253}, 'checkable': False, 'checked': False, 'clickable': False, 'enabled': True, 'focusable': False, 'focused': False, 'longClickable': False, 'scrollable': False, 'selected': True}

获取元素坐标

x, y = self.d(text="行情").center() # 元素中心点
x, y = self.d(text="行情").center(offset=(0, 0)) # 元素左上点坐标

截图

截取UI对象

im = d(text="行情").screenshot()
im.save("行情.jpg")

设备截图

d.screenshot("saved.jpg")
d.screenshot().save("saved.png")
cv2.imwrite('saved.jpg', d.screenshot(format='opencv'))

命令行操作

获取指定设备的当前包名和activity

$ python3 -m uiautomator2 --serial SNHVB20C18002195 current
{
    "package": "com.android.settings",
    "activity": ".HWSettings",
    "pid": 11040
}

# python3 -m uiautomator2 可以简写为uiautomator2

$ uiautomator2 --serial SNHVB20C18002195 current
{
    "package": "com.android.settings",
    "activity": ".HWSettings",
    "pid": 11040
}

screenshot: 截图

$ uiautomator2 screenshot screenshot.jpg

uninstall: 卸载

$ uiautomator2 uninstall <package-name> # 卸载一个包
$ uiautomator2 uninstall <package-name-1> <package-name-2> # 卸载多个包
$ uiautomator2 uninstall --all # 全部卸载

stop: 停止应用

$ uiautomator2 stop com.example.app # 停止一个app
$ uiautomator2 stop --all # 停止所有的app

pytest + Uiautomator2实例

测试步骤:

  1. 打开雪球app
  2. 进入行情页面
  3. 点击搜索
  4. 输入“招商银行”
  5. 点击股票代码03968
  6. 断言股票价格

Python代码:

#!/usr/bin/python3
# -*-coding:utf-8-*-

import uiautomator2 as u2

class TestU2():
    def setup(self):
        self._device = '127.0.0.1:7555'
        self._appPackage = 'com.xueqiu.android'
        self._appActivity = '.common.MainActivity'

        self.d = u2.connect_usb(self._device)
        self.d.set_new_command_timeout(300)
        self.d.app_start(self._appPackage, self._appActivity)

    def teardown(self):
        # self.d.app_stop(self._appPackage)
        pass

    def test_uiautomator2(self):
        # 点击 行情
        self.d(className="android.widget.TextView", text="行情").click()
        search_ele = self.d(resourceId="com.xueqiu.android:id/action_search").wait(timeout=3.0)
        assert search_ele == True
        
        # 点击 搜索
        self.d(resourceId="com.xueqiu.android:id/action_search").click()
        
        # 输入
         self.d(resourceId="com.xueqiu.android:id/search_input_text").set_text("招商银行")  # set the text

		# 点击 搜索结果
        self.d.xpath('//*[@text="03968"]').wait(3).click()
        
        # 读取股价
        wait_price = self.d(resourceId="com.xueqiu.android:id/current_price")[0].wait(timeout=3.0)
        if wait_price:
            current_price = self.d(resourceId="com.xueqiu.android:id/current_price")[0].get_text()
            assert float(current_price) < 60
        else:
            assert False

--THE END--
  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章      下一篇文章      查看所有文章
加:2021-07-17 12:14:55  更:2021-07-17 12:14:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/6 13:39:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码