http://www.2cto.com/kf/201411/356056.html
使用Monkeyrunner进行Android自动化的总结

使用Android自动化的方式,不仅可以用来对Android APP进行自动化测试,同样可以用来进行一些其他非常有意思的自动化任务.常用的自动化工具有Monkeyrunner, Robotium, Appium等.Monkeyrunner是Android自带的自动化测试工具,允许用户对Android设备的UI界面进行元素提取,执行touch 和drag等操作,配合HierarchyViewer等模块可以非常方便地进行自动化操作.

首先,用户需要安装好Android开发环境,同时运行Monkeyrunner脚本需要安装Jython环境.Jython允许使用Python 的语法格式来编写自动化测试代码,因此对于Python开发者而言非常有优势.Python中的一些个别模块不能直接用于Jython中,这时就需要安装 适用于Jython版本的,具体方法可参考

http://stackoverflow.com/questions/3256135/importing-python-modules-in-jython. 如安装bottle模块, jython ez_setup.py bottle,然后在使用时导入该模块即可.

1
2
3
import sys
sys.path.append('/home/jython2.5.3/Lib/site-packages/bottle-0.12.7-py2.5.egg')
from bottle import Bottle, run, request, response, get, post

使用Monkeyrunner进行Android自动化大概可以分为以下几种类型的操作:设备及UI界面操作,UI界面元素提取,截图对比等.

1, 设备及UI界面操作

其实,涉及到Android设备的操作,使用开发环境自带的adb已经足够了,而Monkeyrunner也是将adb操作封装了以下而已.常见adb操作如下:

1
2
3
4
5
6
7
8
adb install xxx.apk 安装apk文件
adb shell am start -an com.xxx.xxx/.MainActivity 启动APP
adb shell am force-stop com.xxx.xxx 停止该APP
adb shell input keyevent KEYCODE_HOME 模拟Android的HOME按键
adb -s emulator-5554 shell input text test_to_input 针对特定的一个模拟器进行操作
adb shell input tap x y 模拟屏幕touch操作
adb shell input swipe x1 y1 x2 y2 模拟屏幕滑动操作
adb devices 查看所有在线的Android设备.

详细的adb命令,可以通过adb -h来查询.而Monkeyrunner中对设备的操作如下:

1
2
3
4
5
6
7
8
9
10
11
12
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
device = MonkeyRunner.waitForConnection(5,"emulator-5554")
device.shell("am start -an com.xxx.xxx/.MainActivity")
device.touch(250, 450, 'DOWN_AND_UP')
device.drag((1080/2, 1700),(1080/2, 400),0.5,1)
device.type("text to type")
device.shell("input text" + "text to input")
device.press("KEYCODE_HOME")
# 另外,也可以通过id来进行touch操作,此时可以引入By模块,可以非常方便通过id寻找对应的元素.
from com.android.monkeyrunner.easy import EasyMonkeyDevice, By
easy_device = EasyMonkeyDevice(device)
easy_device.touch(By.id('id/button1'), easy_device.DOWN_AND_UP)

以上方式其实与adb shell的操作是一致的,只是方便用户在Jython脚本文件中调用而已.

2, UI界面元素提取

Monkeyrunner可以通过HierarchyViewer来对UI界面的元素进行解析,解析的结果与DDMS及Android Studio中的Android Device Monitor保持一致.

首先需要先对UI界面进行解析,然后即可通过元素id和其他的属性来提取该元素,并对其所有属性进行解析.

1
2
3
4
5
6
7
8
9
10
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
from com.android.chimpchat.hierarchyviewer import HierarchyViewer
device = MonkeyRunner.waitForConnection(5,"emulator-5554")
hViewer = device.getHierarchyViewer() # 对当前UI视图进行解析
content = hViewer.findViewById('id/content')  # 通过id查找对应元素
memberView = content.children[0]
text = memberView.namedProperties.get('text:mText').value.encode('utf8')
desc = memberView.namedProperties.get('accessibility:getContentDescription()').value.encode('utf8')
mleft = memberView.namedProperties.get('layout:mLeft').value.encode('utf8')
height = memberView.height

使用HierarchyViewer来解析界面的层级关系,并根据id来查找特定元素是我们常用的做法.然 而,Android APP中,会有很多元素是没有对应的id的(这一点,可以通过DDMS或者AVD中解析结果看出来),那么此时,我们如果要精准地找到一个特定元素,就只 能通过进一步解析某个元素的children来实现,会比较麻烦,但往往是非常精准的.

需要注意的是,使用HierarchyViewer并通过id来查找元素偶尔会出错,提示找不到对应的元素.如果遇到实在难以解析出来的元素,可以考虑使 用另一个模块AndroidViewClient进行解析.原理也很类似.甚至有时候,写法比HierarchyViewer简洁得多.

1
2
3
4
5
6
7
vc = ViewClient(device=device, serialno="emulator-5554")
content = vc.findViewById('id/content')
memberView = content.children[0]
text = memberView.getText()
x = memberView.getX()
y = memberView.getY()
height = memberView.getHeight()

AndroidViewClient 的项目地址是https://github.com/dtmilano/AndroidViewClient.使用时候有个注意事项,我们先将 AndroidViewClient写入环境变量中,然后要先导入AndroidViewClient的模块,之后再导入Monkeyrunner及相应 地其他模块,否则会出现找不到AndroidViewClient的错误.至于为什么,大家可以自己尝试一下就明白了.

1
2
3
4
5
6
7
8
9
10
import sys
reload(sys)
sys.setdefaultencoding("utf-8")
ANDROID_VIEW_CLIENT_HOME = os.environ['ANDROID_VIEW_CLIENT_HOME']
sys.path.append(ANDROID_VIEW_CLIENT_HOME + '/src')
from com.dtmilano.android.viewclient import ViewClient, View
 
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
from com.android.monkeyrunner.easy import EasyMonkeyDevice, By
from com.android.chimpchat.hierarchyviewer import HierarchyViewer

不过以上两种方式,都有可能出现UI元素解析失败的情况,原因可能是Android相应工具自身的不完善导致的.因为DDMS和AVD也会经常出现无法解析某个UI界面的情况.

具体的应用场景大家自己斟酌吧,总之,能够完美获取到所需元素即可.

3, 截图对比

这是Monkeyrunner非常有特色的一种方式,常用于通过设备屏幕前后的对比来获取对执行结果的判断.

1
2
3
4
5
6
7
8
9
10
11
path = "/tmp/images"
image = device.takeSnapshot() # 截图
image.writeToFile(path+"主页面".decode('utf-8')+now+'.png','png')
#下面就开始对之前的截图进行对比了
#去文件中找到我们要对比的图片,与该截图image1进行对比
result = MonkeyRunner.loadImageFromFile('/tmp/images/result.png')
#判断图片相识度是否是为90%
if(image.sameAs(result,0.9)):
    log.write("图片对比成功……\n")
else:
    log.write("主页面图片对比失败……\n")

以上,就是通过Monkeyrunner进行Android自动化的一些基本内容.

下边,将大家容易遇到的一些坑记录下来,造福广大人民群众.

Monkeyrunner容易遇到的一些坑:

1, 中文输入的问题

Monkeyrunner默认只支持Ascii编码,所以遇到中文,目前是不能通过adb的input和type进行输入的.那么可以采用复制到PC剪贴板,然后到Android模拟器里边进行粘贴的方式.

但需要注意的是,Android模拟器里边的剪贴板的内容是当前PC的焦点从PC桌面环境切换到模拟器界面瞬间时的剪贴板内 容.常见情况是,通过Monkeyrunner脚本文件将PC环境中剪贴板内容向Android模拟器粘贴时,往往会出现粘贴不上我们想要的内容.此时, 出于调试目的,我们会检查在当前PC环境的剪贴板中,是否是我们需要的内容.然后将鼠标焦点移入模拟器中,常常发现能够粘贴上所需的正确内容.,然而,这 其实是一个时间差的原因,即PC中的剪贴板内容正确,然后切换到模拟器界面,剪贴板内容是从PC环境带过来的,当然是正确的了.相反,我们在 Monkeyrunner脚本执行后,在剪贴板操作之前即将当前PC的焦点切换到模拟器中,会发现剪贴板内容是不正确的.说得有点乱,大家可以好好琢磨, 自己实践一下.

github上有位同学写了一个小的工具,可以非常方便地执行Android模拟器中的剪贴板操 作,https://github.com/bingwei/inputchineseviaadb.非常好用,大家可以试一试.当然,遇到一些特殊字 符,还是需要做一些简单地转义等操作的.

2, Monkeyrunner脚本中各个操作的耗时问题

在Monkeyrunner脚本执行过程中,使用HierarchyViewer以及AndroidViewClient进 行界面元素解析时,会发现findViewById操作的时间消耗很大.尤其是该UI界面上元素非常多的时候,耗时非常明显.然而,涉及到界面切换时,我 们常常会根据当前界面中是否包含某个id的元素来判断界面是否切换成功.那么,在大多数情况下,我们没有必要根据id来判断当前界面,通过 windowName = device.getHierarchyViewer().focusedWindowName()这种方式,已经足够我们进行绝大多数的UI界面判断 了,并且在效率上绝对不是一个数量级的提升.

3, 涉及到UI界面之间切换的算法问题

我们常常会遇到,明明就在几个特定的UI界面之间相互切换,但由于Android自动化环境及工具自身的不稳定性,经常导致 屏幕切换延迟,点击或切换不成功,APP卡住甚至闪退等一些非常苦恼的问题.那么这就是考验编码能力和算法功底的时候.在这一点上,非常感谢教授同学的帮 助,赞一个.

我们可以预先定义一个所有常见界面的focusdWindowName及屏幕切换所需的操作行为的结构体,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
SCREEN_SWITCH_ACTION = {
    'Activity1': {
        'Activity1': None,
        'Activity2': ('LEFT_DOWN', 'Activity1'), # 如,从Activity2切换到Activity1需要做LEFT_DOWN的操作.
        'Activity3': ('LEFT_DOWN', 'Activity1'),
    },
    'Activity2': {
        'Activity1': ('MID_DOWN', 'Activity2'),
        'Activity2': None,
        'Activity3': ('MID_DOWN', 'Activity2'),
    },
    'Activity3': {
        'Activity1': ('RIGHT_DOWN', 'Activity3'),
        'Activity2': ('RIGHT_DOWN', 'Activity3'),          
        'Activity3': None,
    },
}

如上,该字典中key是目标屏幕,其value值即代表了从当前屏幕切换到目标屏幕所需的操作行为.其中,LEFT_DOWN等可以是简单地touch一 个button,也可以写出一个负责的根据界面及元素来决定操作行为的负责操作的集合.有了如上的这种结构体,我们只需要写一个对应的算法,在屏幕切换时 从该结构体中解析操作并执行即可.诸如屏幕等待,失败重试之类的容错机制,都可以随意添加了.

其实,涉及到这个算法层面的问题,研究和改进的空间实在是太大了.有兴趣的同学可以更深入的讨论,欢迎指教.

当然,除了Monkeyrunner, Robotium和Appium等工具也都是使用率非常高的,各有优劣吧.
以上这些,就是本次Monkeyrunner自动化的一些总结,写的比较简略,欢迎批评指正.

使用Monkeyrunner进行Android自动化的总结的更多相关文章

  1. Android自动化学习笔记:编写MonkeyRunner脚本的几种方式

    ---------------------------------------------------------------------------------------------------- ...

  2. Android自动化学习笔记之MonkeyRunner:官方介绍和简单实例

    ---------------------------------------------------------------------------------------------------- ...

  3. Android自动化测试之Monkeyrunner学习笔记(一)

    Android自动化测试之Monkeyrunner学习笔记(一) 因项目需要,开始研究Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括Monkey.Monkeyr ...

  4. android自动化之monkeyrunner

    一.使用CMD命令打开模拟器 运行monkeyrunner之前必须先运行相应的模拟器或连上设备,不然monkeyrunner无法连接设备. 1.1  用Elipse打开Android模拟器或在CMD中 ...

  5. Android自动化测试之MonkeyRunner

    1.Monkeyrunner简介 Monkeyrunner是Android系统自带的四大自动化测试工具之一,其他三个是Monkey.CTS.Benchmark:Monkeyrunner需要通过Andr ...

  6. Android自动化压力测试快速入门教程(图解)——MonkeyRunner

    一.MonkeyRunner测试环境配置(转自) 1.  android-sdk 下载地址:http://www.android-doc.com/sdk/index.html 下载完成后,只需要解压就 ...

  7. [转] Android自动化测试之使用java调用monkeyrunner(五)

    Android自动化测试之使用java调用monkeyrunner 众所周知,一般情况下我们使用android中的monkeyrunner进行自动化测试时,使用的是python语言来写测试脚本.不过, ...

  8. [转] android自动化测试之MonkeyRunner使用实例(三)

    一.使用CMD命令打开模拟器 运行monkeyrunner之前必须先运行相应的模拟器或连上设备,不然monkeyrunner无法连接设备. 1.1  用Elipse打开Android模拟器或在CMD中 ...

  9. [转] android自动化之MonkeyRunner测试环境配置(一)

    Android自动化测试之MonkeyRunner 一.Android自动化测试之环境搭建 1.1  Android-sdk介绍 ¢ SDK(Software development kit)软件开发 ...

随机推荐

  1. Python lambda介绍(转)

    在学习python的过程中,lambda的语法时常会使人感到困惑,lambda是什么,为什么要使用lambda,是不是必须使用lambda? 下面就上面的问题进行一下解答. 1.lambda是什么? ...

  2. 求高精度幂(poj1001)

    Description Problems involving the computation of exact values of very large magnitude and precision ...

  3. java.lang.NegativeArraySizeException

    两台android设备发送图片. 发送端: Socket socket = null; try { socket = new Socket(ip, 8888); byte[] bytes = Scre ...

  4. [SDOI2005]反素数ant

    题目描述 对于任何正整数x,其约数的个数记作g(x).例如g(1)=1.g(6)=4. 如果某个正整数x满足:g(x)>g(i) 0<i<x,则称x为反质数.例如,整数1,2,4,6 ...

  5. 【最短路】NOIP模拟赛 虫洞

    虫洞 [题目描述] N个虫洞,M条单向跃迁路径.从一个虫洞沿跃迁路径到另一个虫洞需要消耗一定量的燃料和1单位时间.虫洞有白洞和黑洞之分.设一条跃迁路径两端的虫洞质量差为delta. 1. 从白洞跃迁到 ...

  6. Problem C: 调用函数,求a+aa+aaa+....+aa...aa(n个a)

    #include <stdio.h> int fn(int a,int n)//定义函数 { ; ;i<=n;i++) { m=m+a;//当a=3时,m=3,然后a=30,m=33 ...

  7. 原生js实现Ajax请求

    总的来说,Ajax是与服务器交换数据并更新部分网页的艺术,在不重新加载整个网页的情况下,异步请求数据并刷新页面.举一个小的例子:Goole搜索页面.当用户在输入框输入关键字的时候,JavaScript ...

  8. [NHibernate]使用AttributeNHibernate.Mapping.Attributes

    系列文章 [Nhibernate]体系结构 [NHibernate]ISessionFactory配置 [NHibernate]持久化类(Persistent Classes) [NHibernate ...

  9. nodejs调试利器:supervisor

    测试多了,是不是感觉每次要重新node一次app.js,很烦恼? 用supervisor,只有有改动,页面刷新就可以看到效果,不用重启node.js 安装: npm -g install superv ...

  10. 《Windows驱动开发技术详解》之StartIO例程

    内容中包含 base64string 图片造成字符过多,拒绝显示