1.目的(原创文章,转载请注明出处~)
主要为指引开展android平台应用的稳定性测试,尽可能地在应用发布前发现crash及anr等问题并修复,android平台的应用均适用并可定制接入。
主要达到下班前执行,第二天上班时查看分析测试日志的目的,实现了以下核心功能:
a、可批量同时对多台android手机进行测试;
b、可对一台android设备选择模式为连续多次测试;
c、输入保存monkey运行时日志文件和用logcat抓取app运行时日志
2.环境搭建
3.1、java jdk环境配置:安装jdk,并添加系统环境变量,点击参考
3.2、android sdk环境配置(建议使用方法2):
方法1:下载安装SDK for Windows:
设置sdk下面tools的环境变量
右击“计算机”-》属性-》高级系统设置-》环境变量-》
点击Path,将“D:\android-sdk-windows\platform-tools”添加到变量值中,与之前的变量值用“;”隔开。
方法2:可通过安装android模拟器的方式实现(较简单),可直接搜索下载droid 4x海马玩模拟器。
安装成功后设置环境变量:
右击“计算机”-》属性-》高级系统设置-》环境变量-》
点击Path,将“D:\Program Files\Droid4X”添加到变量值中,与之前的变量值用“;”隔开。
3.3、python环境搭建:安装python 2.7或3.5版本,并添加系统环境变量,点击参考
3.测试前准备
2.1、每台待测android设备手工安装好待测试app应用,若为需要登录才能使用app功能的应用请先手工完成登录操作,并确保跳过相应的app新手引导页。
2.2、待测试android设备通过USB数据线与PC主机相连,并通过360手机助手之类的工具确保手机与pc是可进行adb调试的)。如下所示,在cmd命令中输入adb devices,所列的设备如果状态为device则代表该设备已可与PC通过adb调试通信。(建议一台PC机所连接android设备不超过5)
2.3、执行monkey测试前,一定要确保屏幕处于解锁状态。设置屏幕超时时间为最大时间(设置->显示->休眠->30分钟或者从不)。以防测试过程中手机锁屏,影响monkey测试。
4.测试工具介绍
4.1 monkey工具
Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。点击详细了解monkey
4.2 adb工具
Android调试桥接器,简称adb,是用于管理模拟器或真机状态的万能工具。Adb工具在本稳定性测试方案中主要作为PC与手机的通信桥梁。点击详细了解adb
4.3 python脚本功能说明
此脚本可以达到同时进行多台手机的测试,并可选择单次测试和同一台设备多次连续测试,具体功能说明如下:
Python脚本执行说明:在pc上快捷键“win+R”打开cmd命令行,输入:python E:\monkey_test\monkey_dist.py(脚本的绝对路径)
1 # -*- coding: GB2312 -*- 2 import os 3 import os.path 4 import time 5 import glob 6 7 # 删除已有测试cmd脚本 8 path = "E:\\monkey_test\\" 9 for file in glob.glob(os.path.join(path, '*.cmd')): 10 os.remove(file) 11 12 os.system("cls") # os.system("cls")具有清屏功能 13 rt = os.popen('adb devices').readlines() # os.popen()执行系统命令并返回执行后的结果 14 n = len(rt) - 2 15 print "当前已连接待测手机数为:" + str(n) 16 aw = raw_input("是否要开始你的monkey测试,请输入(yes or no): ") 17 18 if aw == 'yes': 19 print "monkey测试即将开始...." 20 count = raw_input("请输入你要进行的monkey测试次数: ") 21 testmodel = raw_input("请输入你是要进行单次测试还是多次连续测试,请输入(1-代表单次测试,2-代表多次连续测试): ") 22 ds = range(n) 23 for i in range(n): 24 nPos = rt[i + 1].index("\t") 25 ds[i] = rt[i + 1][:nPos] 26 dev = ds[i] 27 promodel = os.popen( 28 "adb -s " + dev + ' shell cat /system/build.prop | find "ro.product.model="').readlines() # 获取手机型号 29 #modelname = ('').join(promodel) # 将list转为字符串 30 modelname = promodel[0] #从list中取出第一个值 31 model = modelname[17:].strip('\r\n') 32 proname = os.popen( 33 "adb -s " + dev + ' shell cat /system/build.prop | find "ro.product.brand="').readlines() # 获取手机名称 34 roname = proname[0] 35 name = roname[17:].strip('\r\n') 36 packagename = os.popen( 37 "adb -s " + dev + ' shell pm list packages | find "xxx"').readlines() 38 package = packagename[0] 39 pk = package[8:].strip('\r\n') 40 if pk == 'com.xxx': 41 filedir = os.path.exists("E:\\monkey_test\\") 42 if filedir: 43 print "File Exist!" 44 else: 45 os.mkdir("E:\\monkey_test\\") 46 devicedir = os.path.exists("E:\\monkey_test\\" +name + '-' + model + '-' + dev) 47 if devicedir: 48 print "File Exist!" 49 else: 50 os.mkdir("E:\\monkey_test\\" +name + '-' + model + '-' + dev) # 按设备ID生成日志目录文件夹 51 wl = open("E:\\monkey_test\\" +name + '-' + model + '-' + ds[i] + '-logcat' + '.cmd', 'w') 52 #wl.write('adb -s ' + dev + ' logcat -v time ACRA:E ANRManager:E System.err:W *:S') 53 wl.write('adb -s ' + dev + ' logcat -v time *:W') 54 wl.write('> E:\\monkey_test\\' + '"'+ name + '-'+ model + '-' + dev + '"' + '\\logcat_%random%.txt\n') 55 wl.close() 56 if testmodel == '1': 57 wd = open("E:\\monkey_test\\" +name + '-' + model + '-' + ds[i] + '-device' + '.cmd', 'w') 58 wd.write( 59 'adb -s ' + dev + ' shell monkey -p com.xxx --monitor-native-crashes --ignore-crashes --pct-syskeys 5 --pct-touch 55 --pct-appswitch 20 --pct-anyevent 20 --throttle 200 -s %random% -v ' + count) # 选择设备执行monkey 60 wd.write('> E:\\monkey_test\\' + '"'+ name + '-'+ model + '-' + dev + '"' + '\\monkey_%random%.txt\n') 61 wd.write('@echo 测试成功完成,请查看日志文件~') 62 wd.close() 63 elif testmodel == '2': 64 wd = open("E:\\monkey_test\\" +name + '-' + model + '-' + ds[i] + '-device' + '.cmd', 'w') 65 wd.write(':loop') 66 wd.write('\nset /a num+=1') 67 wd.write('\nif "%num%"=="4" goto end') 68 wd.write( 69 '\nadb -s ' + dev + ' shell monkey -p com.xxx --monitor-native-crashes --ignore-crashes --pct-syskeys 5 --pct-touch 55 --pct-appswitch 20 --pct-anyevent 20 --throttle 200 -s %random% -v ' + count) # 选择设备执行monkey 70 wd.write('> E:\\monkey_test\\' + '"'+ name + '-'+ model + '-' + dev + '"' + '\\monkey_%random%.txt\n') 71 wd.write('@echo 测试成功完成,请查看日志文件~') 72 wd.write('\nadb -s '+ dev +' shell am force-stop '+ pk) 73 wd.write('\n@ping -n 15 127.1 >nul') 74 wd.write('\ngoto loop') 75 wd.write('\n:end') 76 wd.close() 77 else: 78 print "请确认待测手机"+name + '-' + model +"未安装com.xxx~" 79 80 # 执行上述生成的cmd脚本path='E:\\monkey_test\\' 81 for file in os.listdir(path): 82 if os.path.isfile(os.path.join(path, file)) == True: 83 if file.find('.cmd') > 0: 84 os.system('start ' + os.path.join(path, '"' + file + '"')) # dos命令中文件名如果有空格,需加上双引号 85 time.sleep(1) 86 elif aw == 'no': 87 print('请重新确认所有待测手机是否已通过adb命令连接至pc!') 88 else: 89 print "测试结束,输入非法,请重新输入yes or no!"
1.查找当前已连接的测试设备;
2.设置当前要进行的monkey测试次数;
3.设置要进行的测试模式:单次or 多次连续;
4.完成1~3步后,会由python生成相应的android设备的cmd批处理脚本,然后自动扫描执行所有已生成的批处理脚本,以进行monkey稳定性测试。
5、测试结果分析
查看测试日志(进入日志文件夹E:\monkey_test,目前会同时保存monkey运行时的日志和logcat抓取app运行时的实时日志,monkey日志主要关注是否含关键字: crash、exception、anr,logcat日志主要关注是否含关键字:E/ACRA和weloop相关的exception。目前先手工搜索进行检查,日志分析工具后续提供~)
如下所示,某次测试中导致APP崩溃的现象,logcat日志如下(将有效的异常日志提交给相应的开发同学进行确认问题所在):
06-03 14:04:26.730 E/ACRA ( 9152): ACRA caught a RuntimeException exception for com.xx.xxx.xxx.xxx. Building report.
06-03 14:04:27.229 W/ActivityManager( 718): Activity pause timeout for ActivityRecord{2e729252 u0 com.xx.xxx.xxx.xxx./pl.gatti.dgcam.DgCamActivityForTommy2 t874 f}
06-03 14:04:28.238 W/recents.Performance( 934): preload while task Change spend : 1
06-03 14:04:29.761 E/ACRA ( 9152): com.xx.xxx.xxx.xxx. fatal error : Unable to pause activity {com.xx.xxx.xxx.xxx./pl.gatti.dgcam.DgCamActivityForTommy2}: java.lang.RuntimeException: Camera is being used after Camera.release() was called
06-03 14:04:29.761 E/ACRA ( 9152): java.lang.RuntimeException: Unable to pause activity {com.xx.xxx.xxx.xxx./pl.gatti.dgcam.DgCamActivityForTommy2}: java.lang.RuntimeException: Camera is being used after Camera.release() was called
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3613)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3568)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.handlePauseActivity(ActivityThread.java:3543)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.access$1000(ActivityThread.java:178)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1557)
06-03 14:04:29.761 E/ACRA ( 9152): at android.os.Handler.dispatchMessage(Handler.java:111)
06-03 14:04:29.761 E/ACRA ( 9152): at android.os.Looper.loop(Looper.java:194)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.main(ActivityThread.java:5779)
06-03 14:04:29.761 E/ACRA ( 9152): at java.lang.reflect.Method.invoke(Native Method)
06-03 14:04:29.761 E/ACRA ( 9152): at java.lang.reflect.Method.invoke(Method.java:372)
06-03 14:04:29.761 E/ACRA ( 9152): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1005)
06-03 14:04:29.761 E/ACRA ( 9152): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:800)
06-03 14:04:29.761 E/ACRA ( 9152): Caused by: java.lang.RuntimeException: Camera is being used after Camera.release() was called
06-03 14:04:29.761 E/ACRA ( 9152): at android.hardware.Camera.lock(Native Method)
06-03 14:04:29.761 E/ACRA ( 9152): at pl.gatti.dgcam.a.b(ProGuard:76)
06-03 14:04:29.761 E/ACRA ( 9152): at pl.gatti.dgcam.DgCamActivityForTommy2.l(ProGuard:555)
06-03 14:04:29.761 E/ACRA ( 9152): at pl.gatti.dgcam.DgCamActivityForTommy2.onPause(ProGuard:547)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.Activity.performPause(Activity.java:6215)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.Instrumentation.callActivityOnPause(Instrumentation.java:1363)
06-03 14:04:29.761 E/ACRA ( 9152): at android.app.ActivityThread.performPauseActivity(ActivityThread.java:3595)
06-03 14:04:29.761 E/ACRA ( 9152): ... 11 more
附:常见问题
1、脚本检测出来的手机数与待测手机数不一致,此时需要手工检查确认是否所有手机USB连接/USB调试模式均已打开;
2、部分华为手机权限未放开,导致logcat未能捕获monkey执行测试时的应用日志;如提示:
则华为手机进入拨号界面输入:*#*#2846579#*#* 依次选择:工程菜单---后台设置----LOG设置---LOG开关 将四个选项点击打开。
3、因为monkey工具为随机事件测试,故会误打开系统的音乐播放器播放音乐。