Android客户端稳定性测试——Monkey
修改时间 |
修改内容 |
修改人 |
2016.6.20 |
创建 |
刘永志 |
2016.6.29 |
完成 |
刘永志 |
Monkey简介:
Android SDK自带的命令行测试工具,向设备发送伪随机事件流,对应用程序进行进行稳定性测试。
Monkey的优势与缺陷:
优势:
- 脱离Case的依赖
- 可封装自动化执行
- 可封装后作为客户端性能测试的驱动
缺陷:
- 完全随机,不可控
-
不支持IOS系统
Monkey命令及参数:
基本语法如下:
$ adb shell monkey [options] <event-count>
如果不指定options,Monkey将以无反馈模式启动,并把事件任意发送到安装在目标环境中的全部包。下面是一个更为典型的命令行示例,它启动指定的应用程序,并向其发送500个伪随机事件:
$ adb shell monkey -p your.package.name -v 500
一些常用的参数信息。
Category |
Option |
Description |
General |
--help |
Prints a simple usage guide.
获取帮助信息。 |
|
-v |
Each -v on the command line will increment the verbosity level. Level 0 (the default) provides little information beyond startup notification, test completion, and final results. Level 1 provides more details about the test as it runs, such as individual events being sent to your activities. Level 2 provides more detailed setup information such as activities selected or not selected for testing.
命令行的每一个-v将增加反馈信息的级别。Level 0(缺省值)除启动提示、测试完成和最终结果之外,提供较少信息。Level 1提供较为详细的测试信息,如逐个发送到Activity的事件。Level 2提供更加详细的设置信息,如测试中被选中的或未被选中的Activity。 |
Events
事件 |
-s <seed> |
Seed value for pseudo-random number generator. If you re-run the Monkey with the same seed value, it will generate the same sequence of events.
伪随机数生成器的seed值。如果用相同的seed值再次运行Monkey,它将生成相同的事件序列。 |
|
--throttle <milliseconds> |
Inserts a fixed delay between events. You can use this option to slow down the Monkey. If not specified, there is no delay and the events are generated as rapidly as possible.
在事件之间插入固定延迟。通过这个选项可以减缓Monkey的执行速度。如果不指定该选项,Monkey将不会被延迟,事件将尽可能快地被产成。 |
|
--pct-touch <percent> |
Adjust percentage of touch events. (Touch events are a down-up event in a single place on the screen.)
调整触摸事件的百分比(触摸事件是一个down-up事件,它发生在屏幕上的某单一位置)。 |
|
--pct-motion <percent> |
Adjust percentage of motion events. (Motion events consist of a down event somewhere on the screen, a series of pseudo-random movements, and an up event.)
调整动作事件的百分比(动作事件由屏幕上某处的一个down事件、一系列的伪随机事件和一个up事件组成)。 |
|
--pct-trackball <percent> |
Adjust percentage of trackball events. (Trackball events consist of one or more random movements, sometimes followed by a click.)
调整轨迹事件的百分比(轨迹事件由一个或几个随机的移动组成,有时还伴随有点击)。 |
|
--pct-nav <percent> |
Adjust percentage of "basic" navigation events. (Navigation events consist of up/down/left/right, as input from a directional input device.)
调整"基本"导航事件的百分比(导航事件由来自方向输入设备的up/down/left/right组成)。 |
|
--pct-majornav <percent> |
Adjust percentage of "major" navigation events. (These are navigation events that will typically cause actions within your UI, such as the center button in a 5-way pad, the back key, or the menu key.)
调整"主要"导航事件的百分比(这些导航事件通常引发图形界面中的动作,如:5-way键盘的中间按键、回退按键、菜单按键) |
|
--pct-syskeys <percent> |
Adjust percentage of "system" key events. (These are keys that are generally reserved for use by the system, such as Home, Back, Start Call, End Call, or Volume controls.)
调整"系统"按键事件的百分比(这些按键通常被保留,由系统使用,如Home、Back、Start Call、End Call及音量控制键)。 |
|
--pct-appswitch <percent> |
Adjust percentage of activity launches. At random intervals, the Monkey will issue a startActivity() call, as a way of maximizing coverage of all activities within your package.
调整启动Activity的百分比。在随机间隔里,Monkey将执行一个startActivity()调用,作为最大程度覆盖包中全部Activity的一种方法。 |
|
--pct-anyevent <percent> |
Adjust percentage of other types of events. This is a catch-all for all other types of events such as keypresses, other less-used buttons on the device, and so forth.
调整其它类型事件的百分比。它包罗了所有其它类型的事件,如:按键、其它不常用的设备按钮、等等。 |
Constraints
约束限制 |
-p <allowed-package-name> |
If you specify one or more packages this way, the Monkey will only allow the system to visit activities within those packages. If your application requires access to activities in other packages (e.g. to select a contact) you'll need to specify those packages as well. If you don't specify any packages, the Monkey will allow the system to launch activities in all packages. To specify multiple packages, use the -p option multiple times — one -p option per package.
如果用此参数指定了一个或几个包,Monkey将只允许系统启动这些包里的Activity。如果你的应用程序还需要访问其它包里的Activity(如选择取一个联系人),那些包也需要在此同时指定。如果不指定任何包,Monkey将允许系统启动全部包里的Activity。要指定多个包,需要使用多个 -p选项,每个-p选项只能用于一个包。 |
|
-c <main-category> |
If you specify one or more categories this way, the Monkey will only allow the system to visit activities that are listed with one of the specified categories. If you don't specify any categories, the Monkey will select activities listed with the category Intent.CATEGORY_LAUNCHER or Intent.CATEGORY_MONKEY. To specify multiple categories, use the -c option multiple times — one -c option per category.
如果用此参数指定了一个或几个类别,Monkey将只允许系统启动被这些类别中的某个类别列出的Activity。如果不指定任何类别,Monkey将选 择下列类别中列出的Activity: Intent.CATEGORY_LAUNCHER或Intent.CATEGORY_MONKEY。要指定多个类别,需要使用多个-c选项,每个-c选 项只能用于一个类别。 |
Debugging
调试 |
--dbg-no-events |
When specified, the Monkey will perform the initial launch into a test activity, but will not generate any further events. For best results, combine with -v, one or more package constraints, and a non-zero throttle to keep the Monkey running for 30 seconds or more. This provides an environment in which you can monitor package transitions invoked by your application.
设置此选项,Monkey将执行初始启动,进入到一个测试Activity,然后不会再进一步生成事件。为了得到最佳结果,把它与-v、一个或几个包约 束、以及一个保持Monkey运行30秒或更长时间的非零值联合起来,从而提供一个环境,可以监视应用程序所调用的包之间的转换。 |
|
--hprof |
If set, this option will generate profiling reports immediately before and after the Monkey event sequence. This will generate large (~5Mb) files in data/misc, so use with care. See Traceview for more information on trace files.
设置此选项,将在Monkey事件序列之前和之后立即生成profiling报告。这将会在data/misc中生成大文件(~5Mb),所以要小心使用它。 |
|
--ignore-crashes |
Normally, the Monkey will stop when the application crashes or experiences any type of unhandled exception. If you specify this option, the Monkey will continue to send events to the system, until the count is completed.
通常,当应用程序崩溃或发生任何失控异常时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成。 |
|
--ignore-timeouts |
Normally, the Monkey will stop when the application experiences any type of timeout error such as a "Application Not Responding" dialog. If you specify this option, the Monkey will continue to send events to the system, until the count is completed.
通常,当应用程序发生任何超时错误(如"Application Not Responding"对话框)时,Monkey将停止运行。如果设置此选项,Monkey将继续向系统发送事件,直到计数完成。 |
|
--ignore-security-exceptions |
Normally, the Monkey will stop when the application experiences any type of permissions error, for example if it attempts to launch an activity that requires certain permissions. If you specify this option, the Monkey will continue to send events to the system, until the count is completed.
通常,当应用程序发生许可错误(如启动一个需要某些许可的Activity)时,Monkey将停止运行。如果设置了此选项,Monkey将继续向系统发送事件,直到计数完成。 |
|
--kill-process-after-error |
Normally, when the Monkey stops due to an error, the application that failed will be left running. When this option is set, it will signal the system to stop the process in which the error occurred. Note, under a normal (successful) completion, the launched process(es) are not stopped, and the device is simply left in the last state after the final event.
通常,当Monkey由于一个错误而停止时,出错的应用程序将继续处于运行状态。当设置了此选项时,将会通知系统停止发生错误的进程。注意,正常的(成功的)结束,并没有停止启动的进程,设备只是在结束事件之后,简单地保持在最后的状态。 |
|
--monitor-native-crashes |
Watches for and reports crashes occurring in the Android system native code. If --kill-process-after-error is set, the system will stop.
监视并报告Android系统中本地代码的崩溃事件。如果设置了--kill-process-after-error,系统将停止运行。 |
|
--wait-dbg |
Stops the Monkey from executing until a debugger is attached to it.
停止执行中的Monkey,直到有调试器和它相连接。 |
来自 <https://developer.android.com/studio/test/monkey.html>
Monkey使用实例:
- 下载AndroidSDK
-
配置Android环境变量
添加环境变量Android_HOME, 值是Android SDK的路径;
Android SDK下的platform-tools路径和tools路径添加到环境变量Path (%ANDROID_HOME%\platform-tools; %ANDROID_HOME%\tools;)
- 获取包名
- 连接设备或启动模拟器
- 执行Monkey测试
adb shell monkey -p com.nyts.sport --pct-touch 30 --pct-motion 30 --pct-trackball 0 --pct-nav 0 --pct-majornav 20 --pct-appswitch 10 --pct-anyevent 10 -s(指定seed值) 12867 -v --throttle(指定时间间隔) 300 20000 >MonkeyTest.txt |
-
Monkey执行结果分析
打开日志文件,查找关键字"ANR","Fatal","CRASH","Exception","androidruntime","out of memory", "null pointer"若存在,则说明发生异常。
打开日志文件,查找关键字"Finished",若存在,则证明Monkey正常结束
-
收集出错相关信息,发给研发
- 执行后的手机截图
- monkey手机的日志文件
- monkey的测试结果
- 被测试手机信息
Monkey使用技巧:
Monkey的运行停止条件:
- 如果限定了Monkey运行在一个或几个特定的包上,当试图跳转到其他包的时候,停止运行。
- 如果应用程序崩溃或接收到任何失控异常,Monkey将停止并报错。
- 如果应用程序产生了应用程序不响应(application not responding)的错误,Monkey将会停止并报错。(ANR异常)
- 向系统发送指定的事件,并计数完成
自动化集成:
DOS版本日志检查:
@ECHO OFF
ECHO.:::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.:: 分析Monkey日志 ::
ECHO.:: 作者:Findyou ::
ECHO.:: 版本 V1.0.1 ::
ECHO.:: 时间:2014.08.26 ::
ECHO.:::::::::::::::::::::::::::::::::::::::::::::::::
REM 方法一:手动设置Monkey日志路径
SET monkeyLogFile=F:\Monkey\20140808\FindyouV1.0.0\20140825181801_monkey.log
REM 方法二:直接将Monkey日志拖到此bat文件上
IF NOT "%1"=="" SET monkeyLogFile=%1
ECHO.[ INFO ] Monkey日志: %monkeyLogFile%
ECHO.[ INFO ] 开始分析
SET blnException=0
ECHO.
ECHO.
REM 如果觉得分析太快,没有感觉,把下面注释去掉假装分析中,有停顿感
REM ping -n 2 127.0.0.1>nul
::ANR日志
FOR /F "delims=" %%a IN ('FINDSTR /C:"ANR" %monkeyLogFile%') DO (
SET strANR=%%a
)
::崩溃日志
FOR /F "delims=" %%a IN ('FINDSTR /C:"CRASH" %monkeyLogFile%') DO (
SET strCRASH=%%a
)
::异常日志
FOR /F "delims=" %%a IN ('FINDSTR /C:"Exception" %monkeyLogFile%') DO (
SET strException=%%a
)
::正常
FOR /F "delims=" %%a IN ('FINDSTR /C:"Monkey finished" %monkeyLogFile%') DO (
SET strFinished=%%a
)
IF NOT "%strANR%" == "" (
ECHO.[ INFO ] 分析Monkey日志存在: ANR
ECHO.[ INFO ] ------------------------------------
ECHO. "%strANR%"
SET /a blnException+=1
ECHO.
)
IF NOT "%strCRASH%" == "" (
ECHO.[ INFO ] 分析Monkey日志存在: CRASH
ECHO.[ INFO ] ------------------------------------
ECHO. "%strCRASH%"
SET /a blnException+=1
ECHO.
)
IF NOT "%strException%" == "" (
ECHO.[ INFO ] 分析Monkey日志存在: 异常
ECHO.[ INFO ] ------------------------------------
ECHO. "%strException%"
SET /a blnException+=1
)
IF NOT "%strFinished%" == "" (
ECHO.[ INFO ] 分析Monkey日志存在: 执行成功标记
ECHO.[ INFO ] ------------------------------------
ECHO. "%strFinished%"
ECHO.
) ELSE (
IF %blnException% EQU 0 ECHO.[ INFO ] 分析Monkey日志结果: Monkey执行异常中断,请重新执行Monkey脚本!
ECHO.
)
REM 如果blnException不为0,说明存在异常,改变字体为淡紫色
IF %blnException% NEQ 0 (
Color 0D
ECHO.[ INFO ] 分析Monkey日志结果:存在异常日志,请手工再仔细检查!
ECHO.
) ELSE (
ECHO.[ INFO ] 分析Monkey日志结果:正常
ECHO.
)
ECHO.
ECHO.[ EXIT ] 按任意键关闭窗口...
PAUSE>nul |
DOS版本自动化信息收集:
@ECHO OFF
ECHO.:::::::::::::::::::::::::::::::::::::::::::::::::
ECHO.:: Monkey测试 ::
ECHO.:: 作者:Findyou ::
ECHO.:: 版本 V1.0.1 ::
ECHO.:: 时间:2014.08.25 ::
ECHO.:::::::::::::::::::::::::::::::::::::::::::::::::
IF NOT EXIST %~dp0\config.conf GOTO EXIT
ECHO.[ INFO ] 准备Monkey测试
ECHO.[ INFO ] 读取config.conf中信息
REM 从配置文件中获得包名
FOR /F "tokens=1,2 delims==" %%a in (config.conf) do (
IF %%a == packageName SET packageName=%%b
IF %%a == appEnName SET appEnName=%%b
IF %%a == appversion SET appversion=%%b
)
REM 获取日期,格式为:20140808
SET c_date=%date:~0,4%%date:~5,2%%date:~8,2%
REM 获取得小时,格式为:24小时制,10点前补0
SET c_time=%time:~0,2%
IF /i %c_time% LSS 10 (
SET c_time=0%time:~1,1%
)
REM 组合小时、分、秒,格式为: 131420
SET c_time=%c_time%%time:~3,2%%time:~6,2%
REM 将当运行时间点做为日志文件名
SET logfilename=%c_date%%c_time%
REM 创建当天日期目录及测试APP日志保存目录
IF NOT EXIST %~dp0\%c_date% md %~dp0\%c_date%
SET logdir="%~dp0\%c_date%\%appEnName%%appversion%"
IF NOT EXIST %logdir% (
ECHO.[ Exec ] 创建目录:%c_date%\%appEnName%%appversion%
md %logdir%
)
REM 获得手机信息,显示并保存
adb shell cat /system/build.prop>phone.info
FOR /F "tokens=1,2 delims==" %%a in (phone.info) do (
IF %%a == ro.build.version.release SET androidOS=%%b
IF %%a == ro.product.model SET model=%%b
IF %%a == ro.product.brand SET brand=%%b
)
del /a/f/q phone.info
ECHO.[ INFO ] 读取Phone信息
ECHO. 手机品牌: %brand%
ECHO. 手机型号: %model%
ECHO. 系统版本: Android %androidOS%
ECHO.Phone信息>"%logdir%\%logfilename%_%model%.txt"
ECHO.手机品牌: %brand%>>"%logdir%\%logfilename%_%model%.txt"
ECHO.手机型号: %model%>>"%logdir%\%logfilename%_%model%.txt"
ECHO.系统版本: Android %androidOS%>>"%logdir%\%logfilename%_%model%.txt"
ECHO.
ECHO.[ Exec ] 使用Logcat清空Phone中log
adb logcat -c
REM ECHO.[ INFO ] 暂停2秒...
ping -n 2 127.0.0.1>nul
ECHO.
ECHO.[ INFO ] 开始执行Monkey命令
REM ECHO.[ INFO ] 强制关闭准备测试的APP
adb shell am force-stop %packageName%
:::::::::::::::::Monkey测试命令::::::::::::::::::::::::
::::::::::::修改策略请仅在此区域内修改:::::::::::::::::
ECHO.[ Exec ] adb shell monkey -p %packageName% -s %c_time% --throttle 500 -v -v -v 10000
adb shell monkey -p %packageName% -s %c_time% --throttle 500 -v -v -v 10000>%logdir%\%logfilename%_monkey.log
::::::::::::修改策略请仅在此区域内修改:::::::::::::::::
::::::::::::::::::::::END::::::::::::::::::::::::::::::
ECHO.[ INFO ] 执行Monkey命令结束
ECHO.
ECHO.[ Exce ] 手机截屏
adb shell screencap -p /sdcard/monkey_run_end.png
ECHO.[ INFO ] 拷贝截屏图片至电脑
adb pull /sdcard/monkey_run_end.png %logdir%
cd %logdir%
ren monkey_run_end.png %logfilename%.png
ECHO.
ECHO.[ Exec ] 使用Logcat导出日志
adb logcat -d >%logdir%\%logfilename%_logcat.log
REM ECHO.
REM ECHO.[ Exec ] 导出traces文件
REM adb shell cat /data/anr/traces.txt>%logfilename%_traces.log
REM 待扩展,上传日志至服务器
:EXIT
ECHO.
ECHO.[ INFO ] 请按任意键关闭窗口... PAUSE>nul |
来自 <http://www.cnblogs.com/findyou/p/4106285.html>
Python版本的封装:
导出日志与获取命令:
#coding:utf-8
import sys sys.path.append("..")
import until.Get_FileInfo as Get_FileInfo
''' Created on 2016年4月1日
@author: lyz
备注:用于生成Monkey指令 '''
class Get_MonkeyCmd(): ''' example = "adb shell monkey -p com.nyts.sport --pct-touch 30 --pct-trackball 0 --pct-nav 0 --pct-majornav 20 --pct-appswitch 10 --pct-anyevent 10 -s 12867 -v --throttle 300 20000 > monkeytest.txt" ''' ''' Created on 2016年4月1日 @author: lyz 备注:导出日志文件 ''' def _out_log(self,time): log_out_str = " > ../../report/monkeyreport/" + time + ".txt" return log_out_str
''' Created on 2016年4月1日 @author: lyz 备注:获取monkey命令 ''' def get_Cmd(self,time): monkey_str = "adb shell monkey " parama = Get_FileInfo.Get_FileInfo().get_ConfigString("monkey", "monkey_para") logpath = self._out_log(time) cmd = monkey_str + parama + logpath return cmd
if __name__ == "__main__": result = Get_MonkeyCmd().get_Cmd("888") print (result) |
Monkey执行:
#coding:utf-8
import sys sys.path.append("..")
import os import subprocess import datetime
import until.Get_MonkeyCmd as Get_MonkeyCmd import until.Package_Control as Package_Control import monkeytest.Check_MonkeyReport as Check_MonkeyReport
now = datetime.datetime.now() #时间数组格式 time = now.strftime("%Y%m%d-%H%M%S") #转化为指定格式
class Monkey_TestRun: ''' Created on 2016年4月1日 @author: lyz 备注:启动monkey test ''' def monkey_TestRun(self): cmd_str = Get_MonkeyCmd.Get_MonkeyCmd().get_Cmd(time) print ("Monkey 测试脚本为:" + cmd_str) print ("Monkey测试中...请等待...") os.system(cmd_str) print ("Test END! Begin to Check Report!" + time + ".txt")
check = Check_MonkeyReport.Check_MonkeyReport().check_Log(time) if (check == True): print ("Monkey Report 检查通过,无异常!") else: print ("ERROR:Monkey Report 检查存在异常,请手动再次检查确认!")
if __name__ == "__main__": Monkey_TestRun().monkey_TestRun() |
日志检查:
''' Created on 2016年3月30日
@author: lyz
备注:检查monkey_report模块 ''' #coding:utf-8
class Check_MonkeyReport:
''' Created on 2016年4月5日 @author: lyz 备注:检查是否发生ANR异常(程序卡死5s) ''' def _Get_ANR(self,str_error): contains = str_error.count('ANR') if (contains > 0): print ("找到ANR异常 " + str(contains) + " 处") return False else: return True
''' Created on 2016年4月5日 @author: lyz 备注:检查是否发生Crash ''' def _Get_CRASH(self,str_error): contains = str_error.count('CRASH') if (contains > 0): print ("找到CRASH异常 " + str(contains) + " 处") return False else: return True
''' Created on 2016年4月5日 @author: lyz 备注:检查是否发生Exception异常 ''' def _Get_Exception(self,str_error): contains = str_error.count('Exception') if (contains > 0): print ("找到Exception异常 " + str(contains) + " 处") return False else: return True
''' Created on 2016年4月5日 @author: lyz 备注:检查是否正常结束,Monkey finished字段 ''' def _Get_Finished(self,str_error): contains = str_error.count('Monkey finished') if (contains > 0): print ("测试结束,未发现异常!") return True else: print ("ERROR:Monkey测试异常中断,请重新测试!") return False
''' Created on 2016年4月5日 @author: lyz 备注:检查log文件是否存在异常 ''' def check_Log(self,time): file_path = "../../report/monkeyreport/" + time + ".txt" with open(file_path, 'r') as f: str_log = f.read() if (self._Get_ANR(str_log) and self._Get_CRASH(str_log) and self._Get_Exception(str_log) and self._Get_Finished(str_log)): return True else: return False
if __name__ == "__main__": time = "8888" result = Check_MonkeyReport().check_Log(time) print (result)
|
关于不可控的解决方案:
-
禁用导致不可控控件功能(例如需要登录的功能禁用登出功能)
缺陷:
需要重新打包
相关功能不会覆盖
-
白名单:
方法一:
#! /usr/bin/env monkeyrunner from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice print "get device" #use commands like device.touch and device.drag to simulate a navigation and open my activity #with your activity opened start your monkey test print "end monkey test" |
方法二:
adb shell monkey -p my.package -c android.intent.category.MONKEY -v 500 |
Monkey的思维拓展:
Monkey的封装及性能监控:
封装:可以把获取包名写为配置,每次自动执行,报错后字都手机相关信息
性能监控:结合性能监控工具,在Monkey执行的过程中,同时监控性能,封装成一个工具。由于Monkey的随机性,可以定位一部分性能问题。
感谢:
博客:FINDYOU |
|
testhome恒温 |
testhome社区 |
乐于分享的互联网人 |
互联网搜到的文章 |