Python-UiAutomator使用介绍

声明:本文是Python-UiAutomator知识的梳理,更多更新信息,请参阅Xiaocong的github(https://github.com/xiaocong/uiautomator#uiautomator)。

十分感谢Xiaocong等大侠编写并分享这套Python-UiAutomator的库。


本文主要介绍如下内容,

一, UiAutomator是什么鬼?

二,Python-UiAutomator又是什么鬼?

三, Python-UiAutomator API介绍

四,重要查看工具:UiAutomatorViewer

五,Python编辑器推荐:Geany


让我们怀着一颗好奇的心,逐个看看我们刚刚列出的以上几条吧。


一, UiAutomator是什么鬼?

UiAutomator是google为Android平台开发的跨程序的测试类库(考点:跨程序),可以在Android Studio中用Java Script开发(很久很久以前,大家也用Eclipse开发)。

它支持Android 4.1以及更新的版本,低版本Android不能使用UiAutomator(现实中,很少有产品在使用Android 4及以下的版本了,所以影响很小)。

UiAutomator, 顾名思义主要是针对UI的自动化测试,不仅可以测试用户自己开发的程序,也可以测试系统自带的系统程序,如Setting等。

它支持”黑盒测试“,无需得到要测试程序的代码,就可以测试(这还得多亏了UiAutomatorViewer,这个稍后再讲)。

想获得更多的关于UiAutomator的信息,请移步至Android官网https://developer.android.com/training/testing/ui-automator.html


二,Python-UiAutomator又是什么鬼?

用过Android Studio/Eclipse开发UiAutomator的小伙伴都有体会,UiAutomaor虽然是个好东西,但是不好用。

聪明的程序员,对,就像Xiaocong那样的,为Python和UiAutomator架了一座桥,就是我们今天谈的Python-UiAutomator库,从而力保代码的简洁和优雅。

下面,先来一段Python-UiAutomator代码示例,

from uiautomator import device as d 

d.screen.on() 
d(text="Clock").click()
上面代码的作用是点亮屏幕,然后启动Clock程序。代码简洁利索,十分高效。

那么,如何安装Python-UiAutomator库呢?命令如下,十分简单

$ pip install uiautomator


如何将Pyhon-UiAutomator库导入自己的代码中呢?分一下几种情况,

1. 如果只有一台Android机器,使用下面的代码即可,

from uiautomator import device as d
2. 如果电脑连接多台Android机器,需要指定Serial Number,可以用下面的代码

from uiautomator import Device 

d = Device('014E05DE0F02000E')
3. 如果Android机器连接在另外一条PC主机,则需要指定PC主机的地址和端口,代码如下,

from uiautomator import Device 

d = Device('014E05DE0F02000E', adb_server_host='192.168.1.68', adb_server_port=5037)

关于xiaocong同学的大作,大家可以拜访他的github  https:// github.com/xiaocong/uiautomator#uiautomator

(猜想Xiaocong应该和我们一样是黄皮肤黑眼睛滴:))


三, Python-UiAutomator API介绍

又该画重点了,关于API的介绍是必考噢,切记切记(高中某老师十分喜欢用这个词)

1. 先看看常用的基本API

1.1 获取机器的信息

代码如下,

d.info
下面是可能的结果(因机器不同而异),

{u'displayRotation': 0, 
u'displaySizeDpY': 640, 
u'displaySizeDpX': 360, 
u'screenOn': True, 
u'currentPackageName': u'com.android.launcher3', 
u'productName': u'DeviceX', 
u'displayWidth': 720, 
u'sdkInt': 25, 
u'displayHeight': 1280, 
u'naturalOrientation': True}
1.2 屏幕相关的操作

开关屏幕,代码如下

# Turn on screen 
d.screen.on() 
# Turn off screen 
d.screen.off()
效果等同如下代码,

# wakeup the device 
d.wakeup() 
# sleep the device, same as turning off the screen. 
d.sleep()
查看屏幕是否点亮,代码如下,

if d.screen == "on": # of d.screen != "off" 
    # do something in case of screen on 
    pass 
if d.screen == "off": # of d.screen != "on" 
    # do something in case of screen off 
    pass
1.3 按(软/硬)键操作

先上一小段代码如下,

# press home key 
d.press.home() 
# press back key 
d.press.back() 
# the normal way to press back key 
d.press("back") 
# press keycode 0x07('0') with META  ALT(0x02) on 
d.press(0x07, 0x02)
还支持如下按键的操作,

home
back
left
right
up
down
center
menu
search
enter
recent(recent apps)
volume_up
volume_down
volume_mute
camera
power
更多按键定义,请移步至Android官网  AndroidKeyEvent
1.4 手势相关的存在,包括 短按/长按/滑动/拖拽

短按操作,

# click (x, y) on screen 
d.click(x, y)
长按操作,

# long click (x, y) on screen 
d.long_click(x, y)
滑动操作,

# swipe from (sx, sy) to (ex, ey) 
d.swipe(sx, sy, ex, ey) 
# swipe from (sx, sy) to (ex, ey) with 10 steps 
d.swipe(sx, sy, ex, ey, steps=10)
拖拽操作,

# drag from (sx, sy) to (ex, ey) 
d.drag(sx, sy, ex, ey) 
# drag from (sx, sy) to (ex, ey) with 10 steps 
d.drag(sx, sy, ex, ey, steps=10)
1.5 屏幕相关的操作

获取并设置屏幕的旋转方向,

# retrieve orientation, it may be "natural" or "left" or "right" or "upsidedown" 
orientation = d.orientation 
# set orientation and freeze rotation. 
# notes: "upsidedown" can not be set until Android 4.3. 
d.orientation = "l" # or "left" 
d.orientation = "r" # or "right" 
d.orientation = "n" # or "natural"
冻结/解冻旋转功能,

# freeze rotation 
d.freeze_rotation() 
# un-freeze rotation 
d.freeze_rotation(False)
屏幕截图,

# take screenshot and save to local file "home.png", can not work until Android 4.2. 
d.screenshot("home.png")
获取屏幕层级(hierachy)XML

# dump the widown hierarchy and save to local file "hierarchy.xml" 
d.dump("hierarchy.xml") 
# or get the dumped content(unicode) from return. 
xml = d.dump()
打开通知栏或快速设置栏,

# open notification, can not work until Android 4.3. 
d.open.notification() 
# open quick settings, can not work until Android 4.3.
d.open.quick_settings()
等待窗口休眠或更新,

# wait for current window to idle 
d.wait.idle() 
# wait until window update event occurs 
d.wait.update()

2. Watcher

功能:开启守护进程,当符合条件时,完成特点的动作,如点击按钮等。

2.1 注册Watcher

示例一,

d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .click(text="Force Close")
# d.watcher(name) ## creates a new named watcher.
#  .when(condition)  ## the UiSelector condition of the watcher.
#  .click(target)  ## perform click action on the target UiSelector.
示例二,

d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .press.back.home()
# Alternative way to define it as below
d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .press("back", "home")
# d.watcher(name) ## creates a new named watcher.
#  .when(condition)  ## the UiSelector condition of the watcher.
#  .press.<keyname>.....<keyname>.()  ## press keys one by one in sequence.
#  Alternavie way defining key sequence is press(<keybname>, ..., <keyname>)
2.2 查看某个Watcher是否被触发

d.watcher("watcher_name").triggered 
# true in case of the specified watcher triggered, else false
2.3 移除某个Watcher

# remove the watcher 
d.watcher("watcher_name").remove()
2.4 列出所有已经注册的Watcher

d.watchers 
# a list of all registered wachers' names
2.5 查看是否有任何一个Watcher曾经被触发

d.watchers.triggered 
# true in case of any watcher triggered
2.6 复位所有已经被触发的Watcher

# reset all triggered watchers, after that, d.watchers.triggered will be false. 
d.watchers.reset()
2.7 移除Watcher

# remove all registered watchers 
d.watchers.remove() 
# remove the named watcher, same as d.watcher("watcher_name").remove() 
d.watchers.remove("watcher_name")
2.8 强制运行所有已经注册的Watcher

# force to run all registered watchers 
d.watchers.run()

3. Handler

和Watcher类似,但可以呼叫回调函数,示例代码如下,

def fc_close(device):
  if device(text='Force Close').exists:
    device(text='Force Close').click()
  return True  # return True means to break the loop of handler callback functions.

# turn on the handler callback function
d.handlers.on(fc_close)

# turn off the handler callback function
d.handlers.off(fc_close)

4. 选择器(Selector)

选择器(Selector)是用来识别当前屏幕的对象,它可以通过对象的下列属性来识别,

- 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
示例代码如下,

# To seleted the object ,text is 'Clock' and its className is 'android.widget.TextView' 
d(text='Clock', className='android.widget.TextView')
4.1 通过父子关系选择

# get the child or grandchild 
d(className="android.widget.ListView").child(text="Bluetooth")
4.2 通过宗族关系选择

# get sibling or child of sibling 
d(text="Google").sibling(className="android.widget.ImageView")
4.3 通过相对位置选择,支持left/right/up/down,

示例代码如下,

## select "switch" on the right side of "Wi‑Fi" 
d(text="Wi‑Fi").right(className="android.widget.Switch").click()
4.4 检查当前屏幕UI对象是否存在

d(text="Settings").exists # True if exists, else False 
d.exists(text="Settings") # alias of above property.
4.5 得到UI对象的信息

d(text="Settings").info
4.6 设置/清理可编辑文本的内容,

d(text="Settings").clear_text() # clear the text 
d(text="Settings").set_text("My text...") # set the text
4.7 对UI对象点击

# click on the center of the specific ui object
d(text="Settings").click()
# click on the bottomright corner of the specific ui object
d(text="Settings").click.bottomright()
# click on the topleft corner of the specific ui object
d(text="Settings").click.topleft()
# click and wait until the new window update
d(text="Settings").click.wait()
4.8 对UI对象长按点击

# long click on the center of the specific ui object
d(text="Settings").long_click()
# long click on the bottomright corner of the specific ui object
d(text="Settings").long_click.bottomright()
# long click on the topleft corner of the specific ui object
d(text="Settings").long_click.topleft()
4.9 拖到UI对象到另外一个坐标或者另外一个UI对象

# notes : drag can not be set until Android 4.3.
# drag the ui object to point (x, y)
d(text="Settings").drag.to(x, y, steps=100)
# drag the ui object to another ui object(center)
d(text="Settings").drag.to(text="Clock", steps=50)
4.10 滑动(swipe),支持四个方向,left/right/up/down,

d(text="Settings").swipe.right()
d(text="Settings").swipe.left(steps=10)
d(text="Settings").swipe.up(steps=10)
d(text="Settings").swipe.down()
4.11 双指操作,

d(text="Settings").gesture((sx1, sy1), (sx2, sy2)) \
                  .to((ex1, ey1), (ex2, ey2))
4.12 双指操作,两手指往里捏(In),两手指往外捏(Out)

# notes : pinch can not be set until Android 4.3.
# from edge to center. here is "In" not "in"
d(text="Settings").pinch.In(percent=100, steps=10)
# from center to edge
d(text="Settings").pinch.Out()
4.13 三指手势

d().gestureM((sx1, sy1), (sx2, sy2),(sx3, sy3)) \
                  .to((ex1, ey1), (ex2, ey2),(ex3,ey3))
d().gestureM((100,200),(300,200),(600,200),(100,600),(300,600),(600,900))
4.14 等待UI对象的出现或者消失

# wait until the ui object appears
d(text="Settings").wait.exists(timeout=3000)
# wait until the ui object gone
d(text="Settings").wait.gone(timeout=1000)
4.15 滑动操作,支持水平和垂直滑动,

# fling forward(default) vertically(default) 
d(scrollable=True).fling()
# fling forward horizentally
d(scrollable=True).fling.horiz.forward()
# fling backward vertically
d(scrollable=True).fling.vert.backward()
# fling to beginning horizentally
d(scrollable=True).fling.horiz.toBeginning(max_swipes=1000)
# fling to end vertically
d(scrollable=True).fling.toEnd()
4.16 滚到操作,支持水平和垂直滚动,××支持滚动到指定的UI对象××(必考,切记)

# scroll forward(default) vertically(default)
d(scrollable=True).scroll(steps=10)
# scroll forward horizentally
d(scrollable=True).scroll.horiz.forward(steps=100)
# scroll backward vertically
d(scrollable=True).scroll.vert.backward()
# scroll to beginning horizentally
d(scrollable=True).scroll.horiz.toBeginning(steps=100, max_swipes=1000)
# scroll to end vertically
d(scrollable=True).scroll.toEnd()
# scroll forward vertically until specific ui object appears
d(scrollable=True).scroll.to(text="Security")

四,重要查看工具:UiAutomatorViewer

本文开始有讲到,UiAutomator是黑盒测试,即使没有待测程序的源文件,依然可以进行自动化测试。

程序员没有通天的本领,不可能看看一个待测程序马上就像魔术师一样变出测试代码,所以,我们需要神器----UiAutomatorViewer。

有了它,我们可以把当前屏幕下所有的UI对象看的清清楚楚(穿墙看物)。

这个工具一般放在路径Sdk/tools/bin/uiautomatorviewer(Windows下加后缀.bat)

它有3部分组成,

1. 左边是当前屏幕截图,我们可以选中某个UI对象

2. 右上边是获得的当前层级(Hierarchy)资料,xml格式

3. 右下边是当前选中UI对象的属性

注意:只有当我们点击菜单栏地二个或者第三个图标(带机器人的)的时候,才会获取屏幕的截图和层级(Hierarchy)资料。


五,Python编辑器推荐:Geany

Windows下,比较推荐Geany编辑器,可以很方便完成编辑和编译。

下面简单介绍Geany的Python配置,

1. 点击“New (with Template)” ,打开文件 “main.py”



2. 点击“Build”,选择  “Set Build Commands”



3. 在"Compile"和“Execute”的栏位中,添加完整的python路径名。点击“OK”保存设置,至此设置完成。



4. 点击菜单栏“Execute”图标,运行Python代码,测试设置是否成功。




问&答:

问题一:下面示例中adb_server_host代表另外一台PC Host还是Android Device?

from uiautomator import Device 

d = Device('014E05DE0F02000E', adb_server_host='192.168.1.68', adb_server_port=5037)
答:下面示例中的adb_server_host代表的是Android Device. PC Host 和Android 
Device必须在同一个无线网络下,并且要设置Android Device端的TCP port才可以使用。


问题二:是否可以使用下面的代码实现模拟同时按下2个物理键的功能,比如 Power button + Volume Down?

# press home key 
d.press.home() 
# press back key 
d.press.back() 
# the normal way to press back key 
d.press("back") 
# press keycode 0x07('0') with META  ALT(0x02) on 
d.press(0x07, 0x02)
答:不可以,因为这样需要同时在d.press()中同时送出两个keycode且需要
指定duration, 目前的API没有这个功能。

问题三:关于Watcher,如果已注册的代码被执行过一次后,还会被自动触发吗?

d.watcher("AUTO_FC_WHEN_ANR").when(text="ANR").when(text="Wait") \
                             .click(text="Force Close")
# d.watcher(name) ## creates a new named watcher.
#  .when(condition)  ## the UiSelector condition of the watcher.
#  .click(target)  ## perform click action on the target UiSelector.
答:经过代码测试和网上查询案例,发现Python-UiAutomation的Watcher功能
有bug,已经注册的Wather不会自动触发。如果要实现一直被触发的功能,需要另外
运行一个线程不断呼叫d.watchers.run()。


本文结束!



  • 9
    点赞
  • 97
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值