机器人自动化测试方案(monkeyrunner)
目 录
一、 压力测试工具-monkey
1.1 Monkey简介
1.2 Monkey基本使用
1.3 Monkey工具使用实例
二、 自动化测试工具-monkeyrunner
1.4 Monkeyrunner简介
1.5 Monkeyrunner工具特性
1.6 Monkeyrunner常用API
1.7 测试环境准备
1.8 Monkeyrunner脚本编写
1.9 测试结果分析
一、 压力测试工具-monkey
1.1 Monkey简介
Monkey测试是Android平台自动化测试的一种手段,通过Monkey程序模拟用户触摸屏幕、滑动Trackball、按键等操作来对设备上的程序进行压力测试,检测程序多久的时间会发生异常。 传统意义上,Monkey测试主要针对的是应用的健壮性与稳定性,它通过大量的随机的用户事件来检测应用是否会异常。
1.2 Monkey基本使用
1)常规命令
Adb shell monkey -v
-v:指定打印信息的详细级别,一个 -v增加一个级别 , 默认级别为 0
--help:打印帮助信息
2)事件类命令
-f后接测试脚本名,表示用monkey运行指定的monkey脚本
-s:指定产生随机事件种子值,相同的种子值产生相同的事件序列。如: -s 200
--throttle:每个事件结束后的间隔时间——降低系统的压力(如不指定,系统会尽快的发送事件序列)。如:--throttle 100
--pct-touch:指定触摸事件的百分比,如:--pct-touch 5% ,
相关的还有以下option:
--pct-motion <percent> (滑动事件)、 --pct-trackball <percent> (轨迹球事件) 、 --pct-nav <percent> (导航事件 up/down/left/right)、 --pct-majornav <percent> (主要导航事件 back key 、 menu key)、 --pct-syskeys <percent> (系统按键事件 Home 、Back 、startCall 、 endCall 、 volumeControl)、 --pct-appswitch <percent> (activity之间的切换)、 --pct-anyevent <percent>(任意事件)
3)约束类命令
-p:指定有效的package(如不指定,则对系统中所有package有效),一个-p 对应一个有效package, 如:-p com.ckt -p com.ckt.asura;
-c:activity必须至少包含一个指定的category,才能被启动,否则启动不了;
4)调试类命令
--dbg-no-events:初始化启动的activity,但是不产生任何事件。
--hprof:指定该项后在事件序列发送前后会立即生成分析报告 —— 一般建议指定该项。
--ignore-crashes:忽略崩溃
--ignore-timeouts:忽略超时
--ignore-security-exceptions:忽略安全异常
--kill-process-after-error:发生错误后直接杀掉进程
--monitor-native-crashes:跟踪本地方法的崩溃问题
--wait-dbg:知道连接了调试器才执行monkey测试。
1.3 Monkey工具使用实例
1.需求:对机器人进行设置应用进行压力测试
2.测试准备和执行
在Monkey测试前,必须进行以下准备
Ø 1)设置屏幕超时设置为30分钟,防止进入锁屏状态。
Ø 2)开启ADB模式,连接到PC
Ø 3)开启系统log
Ø 4)在PC上执行 运行—>CMD,在弹出的命令窗口中,输入adb devices,检查设备是否连接 ,在弹出的命令窗口中,输入adb shell,进入Linux Shell ,输入Monkey命令。
如下:
monkey -p com.avatar.settings --ignore-crashes --ignore-timeouts --ignore-native-crashes --pct-touch 30 -s 1 -v -v --throttle 200 100000 2>/sdcard/error.txt 1>/sdcard/info.txt
参数意义:
-p com.avatar.settings |
只仅针对特定包名进行测试 |
--ignore-crashes |
忽略应用程序崩溃(Force & Close错误),继续发送执行事件,直到事件数执行完成 |
--ignore-timeouts |
忽略应用程序发生ANR(Application No Responding)错误时,直到事件数执行完成 |
--ignore-native-crashes |
忽略本地应用程序发生奔溃,直到事件数执行完成 |
--pct-touch 30 |
调整触摸事件为30%。即整个事件过程中触摸事件占30% |
-s 1 |
伪随机数生成器seed值。Seed值为1。相同的seed值再次执行monkey,将产生相同的事件序列 |
-v -v |
日志级别为Leve1 1。将提供较为详细的日志,包括每个发送到Activity的事件信息 |
--throttle 200 |
事件之间延时200毫秒。可以控制monkey的执行速度,如果不指定该选项,monkey事件间将不会延时 |
100000 |
执行事件数为10万次 |
2>/sdcard/error.txt |
Leve1 2日志保存到sdcard 上的error.txt中,主要记录了MONKEY测试时产生的一些ANR、强制关闭等异常 |
1>/sdcard/info.txt |
Leve1 1日志保存到sdcard 上的info.txt中,主要记录了MONKEY测试时发送的各种事件,如触摸事件的位置等等 |
3.测试结果分析
1)初步定位方法:
Monkey测试出现错误后,一般的差错步骤为以下几步:
1、 找到是monkey里面的哪个地方出错
2、 查看Monkey里面出错前的一些事件动作,并手动执行该动作
3、 若以上步骤还不能找出,可以使用之前执行的monkey命令再执行一遍,注意seed值要一样
2)常见错误分析
(1)Null指针异常
空指针异常主要是有NullPointerException异常提示,如果Monkey命令被中断,说明有异常信息并且有对应的打印信息,可以看到如下信息,说明几个问题:
A、android.process.acore该进程出现异常
B、异常信息主要是由于NullPointerException引起的,也就是出现了空指针,导致了acore进程进入debug
***************************************
// CRASH: android.process.acore (pid 1339)
// Short Msg: java.lang.NullPointerException
// Long Msg: java.lang.NullPointerException
// Build Label: android:FIH/msm7627_surf/msm7627_surf/F0X:1.6/DONUT/0001_0_020:e
ng/release-keys
// Build Changelist: -1
// Build Time: 1271397239
// ID:
// Tag: AndroidRuntime
// java.lang.NullPointerException:
// at
(2)debug异常
debug异常主要是由于应用程序本身的错误导致的异常。一般情况下,出现的该问题,很可能在手动测试时也可以测试到。
A、com.android.browser该进程进入debug
B、出现的是IllegalStateException异常,该异常一般多是传递的参数非法或被多次调用时出现的异常
************************************************************************
// CRASH: com.android.browser (pid 5683)
// Short Msg: Connection is not open
// Long Msg: java.lang.IllegalStateException: Connection is not open
// Build Label: android:FIH/msm7627_surf/msm7627_surf/F0X:1.6/DONUT/0001_0_020:eng/release-keys
// Build Changelist: -1
// Build Time: 1271397239
// ID:
// Tag: AndroidRuntime
// java.lang.IllegalStateException: Connection is not open
// at android.net.http.AndroidHttpClientConnection.assertOpen(AndroidHttpClien
tConnection.java:153)
// at android.net.http.AndroidHttpClientConnection.setSocketTimeout(AndroidHtt
pClientConnection.java:195)
// at android.net.http.Connection.openHttpConnection(Connection.java:364)
// at android.net.http.Connection.processRequests(Connection.java:225)
// at android.net.http.ConnectionThread.run(ConnectionThread.java:116)
** System appears to have crashed at event 34155 of 5000000 using seed 0**
(3)操作无响应异常
主要表现在Monkey运行过程中,出现某功能无响应,提示是否“强制关闭“或“等待“,出现ANR,一般是主线程的响应超过5秒,或者BroadcastReceiver没有在10秒内作出响应。这个就是一个比较严重的缺陷。如下可以说明com.avatar.dialog该进程出现的无响应ANR说明有bug。
***************************************
// NOT RESPONDING: com.avatar.dialog (pid 21982)
ANR in com.avatar.dialog
PID: 21982
Reason: Executing service com.avatar.dialog/com.avatar.speech.AvatarSpeechService
(4)其他异常
A、Restart System异常(系统重新启动),即log信息的最后几行会看到Restart System的打印信息,说明设备被自动的重启或断掉,有几个方面的原因
1、运行过程中,存在异常被自动重启
2、在运行过程中,进入设置中的恢复出场设置,导致重启
B、RuntimeException等异常,该问题多出现在操作无响应之后,或者是某应用的服务无法启动或连接时,比如:
***************************************
// CRASH: android.process.media (pid 18925)
// Short Msg: android.content.ActivityNotFoundException
// Long Msg: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.provider.action.MANAGE_ROOT dat=content://com.android.providers.downloads.documents/root/downloads }
// Build Label: rockchip/rk3288/rk3288:4.4.4/KTU84Q/eng.avatarmind.20160606.093049:eng/test-keys
// Build Changelist: eng.avatarmind.20160606.093049
// Build Time: 1465176899000
// java.lang.RuntimeException: Unable to start activity ComponentInfo{com.android.providers.downloads.ui/com.android.providers.downloads.ui.DownloadList}: android.content.ActivityNotFoundException: No Activity found to handle Intent { act=android.provider.action.MANAGE_ROOT dat=content://com.android.providers.downloads.documents/root/downloads }
// at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2249)
// at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2298)
C、StaleDataException、readException等异常, 该信息说明android的数据库操作出现异常
D、IllegalArgumentException等异常,说明向函数传递了一个不正确或不合法的参数
E、低内存异常,主要表现在出现OutOfMemoryError异常或者提示Out of memory,其后果同样表现为抛出OutOfMemoryError异常或者是通过kill process 来杀掉部分进程以释放内存空间,当然如果被kill点关键的进程的话,也就可能导致部分应用会自动的退出。出现该情况时,主要是在进行频繁的进行大量的操作导致的,所以使用手动的方式也是可能进行重现的。
3)详细分析monkey日志:
将执行Monkey生成的log导出并打开查看该log;在log的最开始都会显示Monkey执行的seed值、执行次数和测试的包名。
如info.txt:
***************************************
:Monkey: seed=1 count=100000
:AllowPackage: com.avatar.settings
分析log中的具体信息,方法如下:
查看log中第一个Switch,主要是查看Monkey执行的是哪一个Activity,譬如下面的log中,执行的是com.avatar.settings/.Settings,在下一个swtich之间的,如果出现了崩溃或其他异常,可以在该Activity中查找问题的所在。
***************************************
:Switch: #Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;component=com.avatar.settings/.Settings;end
// Allowing start of Intent { act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] cmp=com.avatar.settings/.Settings } in package com.avatar.settings
在下面的log中,Sending Pointer ACTION_DOWN和Sending Pointer ACTION_UP代表当前执行了一个单击的操作;
***************************************
:Sending Key (ACTION_DOWN): 167 // KEYCODE_CHANNEL_DOWN
:Sending Key (ACTION_UP): 167 // KEYCODE_CHANNEL_DOWN
Sleeping for 200 milliseconds这句log是执行Monkey测试时,throttle设定的间隔时间,每出现一次,就代表一个事件;
***************************************
Sleeping for 200 milliseconds
SendKey(ACTION_DOWN) //KEYCODE_DPAD_DOWN 代表当前执行了一个点击下导航键的操作;
***************************************
:Sending Touch (ACTION_DOWN): 0:(1033.0,37.0)
:Sending Touch (ACTION_UP): 0:(1023.5691,57.83191)
Sending Pointer ACTION_MOVE 代表当前执行了一个滑动界面的操作;
***************************************
Sending Trackball (ACTION_MOVE): 0:(1.0,-3.0)
如果Monkey测试顺利执行完成,在log的最后,会打印出当前执行事件的次数和所花费的时间;// Monkey finished代表执行完成。Monkey执行中断,在log的最后也能查看到当前已执行的次数。Monkey执行完成的log具体如下:
Events injected: 6000
:Dropped: keys=0 pointers=9 trackballs=0 flips=0
## Network stats: elapsed time=808384ms (0ms mobile, 808384ms wifi, 0msnot connected)
// Monkey finished
二、 自动化测试工具-monkeyrunner
1.4 Monkeyrunner简介
monkeyrunner即android SDK中自带的工具之一,此工具提供API可按制android设备或模拟器。monkeyrunner提供了一个API,使用此API写出的程序可以在Android代码之外控制Android设备和模拟器。通过monkeyrunner,可以写出一个Python程序去安装一个Android应用程序或测试包,运行它,向它发送模拟击键,截取它的用户界面图片,并将截图存储于工作站上。monkeyrunner工具的主要目的是用于测试功能/框架水平上的应用程序和设备,或用于运行单元测试套件,但您当然也可以将其用于其它目的。
1.5 Monkeyrunner工具特性
多设备控制:monkeyrunner API可以跨多个设备或模拟器实施测试套件。您可以在同一时间接上所有的设备或一次启动全部模拟器(或统统一起),依据程序依次连接到每一个,然后运行一个或多个测试。您也可以用程序启动一个配置好的模拟器,运行一个或多个测试,然后关闭模拟器。这里就是为什么我们要采用monkeyrunner进行自动化测试,因为我们的系统是需要机器人和监护人端进行交互,大部分用例是需要同时在机器人和监护人端的设备上进行,因此monkeyrunner可以进行多设备控制,正是适合我们项目的最好的自动化测试工具,则其他android自动化工具则无法达到这个目的。
功能测试:monkeyrunner可以为一个应用自动化功能测试。为您提供按键或触摸事件的输入数值,然后观察输出结果的截屏。
回归测试:monkeyrunner可以运行某个应用,并将其结果截屏与既定已知正确的结果截屏相比较,以此测试应用的稳定性。
可扩展的自动化:由于monkeyrunner是一个API工具包,您可以基于Python模块和程序开发一整套系统,以此来控制Android设备。除了使用monkeyrunner API之外,您还可以使用标准的Python os和subprocess模块来调用如adb这样的Android工具。
1.6 Monkeyrunner常用API
1.MonkeyRunner:这个类提供了用于连接monkeyrunner和设备或模拟器的方法,它还提供了用于创建用户界面显示提供了方法。
1) 手势
Void drag(tuple start,tuple end,float duration,integer steps)
通过drag()方法直接传入A点和B点的坐标即可进行拖拽操作
2) 点击
通过touch方法传入A点坐标,并通过DOWN_AND_UP参数直接完成点击
3)输入
Void type(string message)
通过type()方法传入text进行输入
4) 启动应用
Void startActivity(string url,string action,string data,string mimetype,iterable categories,dictionary extras,component component,flags)
通过startActivity方法传入component(包名和应用名组合)即可启动该应用
5)等待
Void sleep(float seconds)
通过sleep()方法传入seconds(单位:秒)进行等待操作
6) 键值事件
Void press(string name,dictionary type)
通过press()方法发送name(keycode)和type(DOWN_AND_UP等)来处理键值事件
7) 输入
String input(string message,string initialvalue,string title,string oktitle,string canceltitle)
通过input()方法在PC端弹出输入框以供用户输入反馈
8) 选择列表框
Integer choice(string message,iterable choices,string title)
通过choice方法即可在PC端弹出选项列表以供用户选择
9) 警告框
Void alert(string message,string title,string oktitle)
通过alert()方法即可在PC端弹出警告框以提示用户
2 .MonkeyDevice:代表一个设备或模拟器。这个类为安装和卸载包、开启Activity、发送按键和触摸事件、运行测试包等提供了方法。
1) 等待设备连接
monkeyDevice waitforconnection(float timeout,string deviceid)
通过waitforconnection()方法等待设备连接到PC,若连接失败,将不会继续进行后续步骤。
2) 安装应用
Void installpackage(string path)
通过installpackage()方法将PC端应用安装到设备上
3)卸载应用
Void removepackage(string package)
通过removepackage()方法卸载设备端应用,并删除该应用数据
4)重启设备
Void reboot(string info)
通过reboot()方法即可重启设备,并在重启后选择需要进入的模式
5)唤醒设备
Void wake()
通过wake()方法即可唤醒设备
6)获取当前设备属性
Object getproperty(string key)
通过getproperty即可获取设备属性
3、MonkeyImage:这个类提供了捕捉屏幕的方法。这个类为截图、将位图转换成各种格式、对比两个MonkeyImage对象、将image保存到文件等提供了方法。
1)截屏
Monkeyimage takesnapshot()
通过monkeydevices的takesnapshot()方法即可获取当前屏幕图像
2)图形保存
通过writetofile()方法即可将截取图像保存为图片
Void writetofile(string path,string format)
3) 图像对比
boolean sameas(monkeyimage other,float percent)
对比当前图像与对比图像是否一致
1.7 测试环境准备
(1)系统所用的语言是python,所有的测试库,脚本,框架均需要此语言编译器的环境,先在windows下安装python工具
(2)jython是python使用java语音的完全实现,系统需要和android交互,因此需要安装jython
(3)准备android开发环境,下载SDK工具包,包中有自动化测试工具monkeyrunner,以及获取控件信息工具hierarchyviewer,安卓调试工具ADB等
1.8 Monkeyrunner脚本编写
用例1:打开并连接wifi。
***************************************
# -*- coding: UTF-8 -*-
#File: wifi1.py
#用例:打开并设置无线网络
print 'Before execution'
#引入本程序所用到的模块
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice, MonkeyImage
#连接机器人设备
device=MonkeyRunner.waitForConnection()
if not device:
print "Please connect a device to start!"
else:
print "Start "
#打开设置
device.startActivity(component = "com.avatar.settings/.Settings")
MonkeyRunner.sleep(2)
#打开无线网络
device.touch(935,262,'DOWN_AND_UP')
MonkeyRunner.sleep(2)
#打开wifi(TP_LINK_4E66)
device.touch(878,454,'DOWN_AND_UP')
MonkeyRunner.sleep(2)
#点击需要输入密码的文本框)
device.touch(530,860,'DOWN_AND_UP')
MonkeyRunner.sleep(2)
#字符串发送到键盘
device.type('avatarmindtest123')
MonkeyRunner.sleep(2)
#点击键盘“完成”键
device.touch(1741,1020,'DOWN_AND_UP')
MonkeyRunner.sleep(2)
#点击"连接”按钮
device.touch(1375,186,'DOWN_AND_UP')
MonkeyRunner.sleep(3)
#截屏
result = device.takeSnapshot()
#图像保存
result.writeToFile('C:\\wifi1.png','png')
#关闭设置,回到首页
device.touch(152,153,'DOWN_AND_UP')
print ('success')
***************************************
查看该图表示用例是否成功执行,如下表示该用例测试pass。
用例2:对平板首页滑屏2次
***************************************
# -*- coding: UTF-8 -*-
#File: huaping1.py
#用例:对平板首页滑屏2次
print 'Before execution'
#引入本程序所用到的模块
from com.android.monkeyrunner import MonkeyRunner
#连接机器人设备
device = MonkeyRunner.waitForConnection()
#截屏
result = device.takeSnapshot()
#保存图片
result.writeToFile('./beforeDrag.png','png')
#从右到左滑动屏幕2次
for i in range(0,2):
device.drag((600,200),(100,200),0.1,12)
MonkeyRunner.sleep(1)
#截屏
result = device.takeSnapshot()
#保存图片
result.writeToFile('./afterDrag.png','png')
print 'success'
***************************************
查看下面分别是beforeDrag.png和afterDrag.png,是否滑动成功,下图表示该用例执行pass
用例3:重复对监护人app做打开关闭操作5次
***************************************
# -*- coding: UTF-8 -*-
#File: open1.py
#用例:重复对监护人app做打开关闭操作5次
print 'Before execution'
#导入方法
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
#连接设备
print ("Connecting device.....")
device = MonkeyRunner.waitForConnection()
if not Device:
print ("Please connect a device to start!")
else:
print ("Device Connected successfully!")
#安装apk
try:
Device.installPackage('C:/apps/GuardianMobile.apk')
print ("Package installed successfully! ")
except:
print ("Package installation failed!")
#设置包名
package = 'com.avatarmind.guardians'
#设置activity名
activity = 'com.avatarmind.guardian.account.LoginActivity'
#循环执行四次
for i in range(1,5):
#打开已安装的应用
print ("Open installed package)
device.startActivity(component = "com.avatarmind.guardians/com.avatarmind.guardian.account.LoginActivity")
#等待5秒
print ("wait 5 sec")
MonkeyRunner.sleep(5)
#关闭应用
print("Quit the application")
device.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
print ("wait 5 sec")
MonkeyRunner.sleep(5)
#卸载APK
try:
print("Uninstall package!")
Device.removePackage("com.avatarmind.guardians")
print("Uninstall package successfully")
except:
print ("Package unintall failed!")
print 'success'
用例4:同时控制监护人端和机器人端的设备(视频通话,应用商城功能可用)
***************************************
# -*- coding: utf-8 -*-
#导入模块
from com.android.monkeyrunner import MonkeyRunner,MonkeyDevice
#连接机器人端,监护人端
Device1=MonkeyRunner.waitForConnection(5,"rk3288")
device2=MonkeyRunner.waitForConnection(5,"lianxiang")
#在监护人端安装APK
Device2.installPackage('E:/GuardianMobile.apk')
package='com.avatarmind.guardians'
activity='.com.avatarmind.guardian.account.LoginActivity'
runComponent=package+'/'+activity
#启动监护人端APK
Device2.startActivity(component=runComponent)
MonkeyRunner.sleep(5)
#操作监护人端某个点
Device2.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
.....
#再操作机器人端某个点
Device1.press('KEYCODE_BACK',MonkeyDevice.DOWN_AND_UP)
.....
***************************************
1.1 测试结果分析
按照每条用例完成测试脚本的编写后,在python的环境中,执行该脚本,即可在自定义的图片存储位置查找图片,分析测试结果的方法就是查看图片,通过查看既定时刻的屏幕截图,即可知道平板在检查点处是否正确的完成了应该完成的功能,测试用例是否测试通过。