一、monkey介绍
1、Monkey程序由Android系统自带,使用Java语言写成,在Android文件系统中的存放路径是: /system/framework/monkey.jar; Monkey.jar程序是由一个名为“monkey”的Shell脚本来启动执行,shell脚本在Android文件系统中 的存放路径是:/system/bin/monkey;
2、作用:测试androidApp的稳定性、健壮性
3、优点:自动生成脚本、日志能直接定位到被测app具体代码行数、随机性
4、缺点:测试目标为整个app,不能指定具体页面、功能
二、框架思路
先来一张图,然后再具体说明
首先肯定需要一台服务器,系统不限,win、mac、linux,都可以
1、持续集成
这个首选肯定是jenkins,主要是用来拉取被测app的代码、打包成apk安装包、定时构建测试
2、下载被测app、安装app(代码)
如果开发已经做好现成的apk供你下载,那就不需要自己拉代码打包了,只需要利用代码把apk下载到你的服务器上,然后调用adb命令安装。
3、测试前的准备工作(UI自动化)
monkey测试前肯定要检查一下,被测app的状态是否符合要求,比如要打开wifi、登录账号、切换测试环境、等等操作,这些就需要用UI自动化来实现,目前有两种框架可选uiautomator2.0和appium,我用的是uiautomator2.0。
4、执行monkey测试(shell脚本)
这里就开始执行monkey测试了,把monkey的指令写到一个shell脚本中,再把shell脚本push到手机里触发执行,该脚本还包含其他功能,比如:统计手机信息(内存、手机型号、app版本、安卓版本等等)、把monkey产生的日志分类,将正常log和异常log分别写入文件,放到手机的指定路径下、记录开始测试时间和结束测试时间、发生崩溃页面的截图功能。这些操作都要写到shell脚本中。
#!/system/bin/sh
dire="/mnt/sdcard/A-monkey/"
filename="/mnt/sdcard/A-monkey/error"
fileout="/mnt/sdcard/A-monkey/result"
filedetail="/mnt/sdcard/A-monkey/detail"
#获取手机信息
info(){
devices_name=`getprop ro.product.model` #设备名称
android_version=`getprop ro.build.version.release` #安卓版本
PHONE_PRODUCER=`getprop ro.product.brand` #手机厂家
SCREEN_SIZE=`wm size` #分辨率
SCREEN_SIZE1=${SCREEN_SIZE#*:} #分辨率
phone_sdk=`getprop ro.build.version.sdk` #sdk版本
phone_udid=`getprop ro.serialno` #udid
phone_ip=`ip -f inet addr show wlan0` #ip地址 ifconfig | grep Mask
phone_ip1=${phone_ip#*inet}
phone_ip2=${phone_ip1%/*}
BabyfsVersion=`dumpsys package cn.babyfs.android|grep versionName` #宝玩app版本
BabyfsVersion1=${BabyfsVersion#*=} #宝玩app版本
WeChatVersion=`dumpsys package com.tencent.mm|grep versionName` #微信的版本
WeChatVersion1=${WeChatVersion#*=} #微信的版本
CpuVersion=`getprop ro.product.board` #处理器的型号
MemTotal=`cat /proc/meminfo|grep MemTotal` #总内存
MemTotal1=${MemTotal#*:} #删除左边
MemTotal2=${MemTotal1%kB*} #删除右边
MemTotal3=`expr $MemTotal2 / 1024` #除法
MemFree=`cat /proc/meminfo|grep MemFree` #可用内存
MemFree1=${MemFree#*:}
MemFree2=${MemFree1%kB*}
MemFree3=`expr $MemFree2 / 1024`
printf "手机厂商: $PHONE_PRODUCER\n">>$filedetail
printf "设备名称: $devices_name\n">>$filedetail
printf "安卓版本: $android_version\n">>$filedetail
printf "分辨率: $SCREEN_SIZE1\n">>$filedetail
printf "处理器型号:$CpuVersion\n">>$filedetail
if [ -z $BabyfsVersion ]; then
printf "宝玩app版本: 没有安装宝玩app\n">>$filedetail
else
printf "宝玩app版本: $BabyfsVersion1\n">>$filedetail
fi
if [ -z $WeChatVersion ]; then
printf "微信版本: 没有安装微信\n">>$filedetail
else
printf "微信版本: $WeChatVersion1\n">>$filedetail
fi
printf "sdk版本: $phone_sdk\n">>$filedetail
printf "udid: $phone_udid\n">>$filedetail
if [ -z $phone_ip2 ]; then
printf "ip地址: 手机未连接wifi\n">>$filedetail
else
printf "ip地址:$phone_ip2\n">>$filedetail
fi
if [ $MemTotal3 -gt 7000 -a $MemTotal3 -le 8000 ]; then
printf "总内存: 8g\n">>$filedetail
elif [ $MemTotal3 -gt 6000 -a $MemTotal3 -le 7000 ]; then
printf "总内存: 7g\n">>$filedetail
elif [ $MemTotal3 -gt 5000 -a $MemTotal3 -le 6000 ]; then
printf "总内存: 6g\n">>$filedetail
elif [ $MemTotal3 -gt 4000 -a $MemTotal3 -le 5000 ]; then #大于and小于等于
printf "总内存: 5g\n">>$filedetail
elif [ $MemTotal3 -gt 3000 -a $MemTotal3 -le 4000 ]; then
printf "总内存: 4g\n">>$filedetail
elif [ $MemTotal3 -gt 2000 -a $MemTotal3 -le 3000 ]; then
printf "总内存: 3g\n">>$filedetail
elif [ $MemTotal3 -gt 1000 -a $MemTotal3 -le 2000 ]; then
printf "总内存: 2g\n">>$filedetail
elif [ $MemTotal3 -gt 500 -a $MemTotal3 -le 1000 ]; then
printf "总内存: 1g\n">>$filedetail
else
printf "内存判断错误\n">>$filedetail
fi
printf "可用内存: $MemFree3 MB\n">>$filedetail
printf "\n">>$filedetail
}
#monkey执行之前的动作
beforemonkey(){
if [ ! -d "$dire" ]; then
mkdir "$dire"
fi
printf "\n">$filedetail
info
printf "测试开始时间 $(date "+%Y-%m-%d %H:%M:%S")\n">>$filedetail
}
#monkeytest(){
#monkey -p cn.fanting.notpadnew --throttle 700 --ignore-crashes --monitor-native-crashes --ignore-security-exceptions --ignore-timeouts --ignore-native-crashes --pct-touch 65 --pct-appswitch 5 --pct-majornav 10 --pct-syskeys 10 --pct-nav 10 -v -v -v 100000 1>/mnt/sdcard/A-monkey/info.txt 2>/mnt/sdcard/A-monkey/error.txt
#}
#有错误就停止测试
monkeytest(){
monkey -p cn.fanting.notpadnew --throttle 700 --monitor-native-crashes --ignore-native-crashes --pct-touch 80 --pct-syskeys 10 --pct-appswitch 10 -v -v -v 50000 1>/mnt/sdcard/A-monkey/info 2>/mnt/sdcard/A-monkey/error
}
#monkey执行之后的动作
aftermonkey(){
screencap -p $dire/error.png #截图
CRASH=`grep -o 'CRASH: ' $filename | wc -l`
error=`grep -o 'error' $filename | wc -l`
ANR=`grep -o 'ANR' $filename | wc -l`
NullPointer=`grep -o 'Short Msg: java.lang.NullPointerException' $filename | wc -l`
ArrayIndexOutOfBounds=`grep -o 'Short Msg: java.lang.ArrayIndexOutOfBoundsException' $filename | wc -l`
lassNotFound=`grep -o 'CShort Msg: java.lang.lassNotFoundException' $filename | wc -l`
ClassCast=`grep -o 'Short Msg: java.lang.ClassCastException' $filename | wc -l`
Arithmetic=`grep -o 'Short Msg: java.lang.ArithmeticException' $filename | wc -l`
IllegalArgument=`grep -o 'Short Msg: java.lang.IllegalArgumentException' $filename | wc -l`
FileNotFound=`grep -o 'Short Msg: java.lang.FileNotFoundException' $filename | wc -l`
NumberFormat=`grep -o 'Short Msg: java.lang.NumberFormatException' $filename | wc -l`
StackOverflow=`grep -o 'Short Msg: java.lang.StackOverflowError' $filename | wc -l`
OutOfMemory=`grep -o 'Short Msg: java.lang.OutOfMemoryError' $filename | wc -l`
IllegalState=`grep -o 'Short Msg: java.lang.IllegalStateException' $filename | wc -l`
UnsatisfiedLink=`grep -o 'Short Msg: java.lang.UnsatisfiedLinkError' $filename | wc -l`
StringIndexOutOfBounds=`grep -o 'Short Msg: java.lang.StringIndexOutOfBoundsException' $filename | wc -l`
Nativecrash=`grep -o 'Short Msg: Native crash' $filename | wc -l`
sleep 2
printf "测试结束时间 $(date "+%Y-%m-%d %H:%M:%S")\n">>$filedetail
printf "\n">>$filedetail
printf "---------------错误日志统计--------------\n">$fileout
printf "%-33s %-10s\n" 错误类型 出现次数>>$fileout
printf "\n">>$fileout
printf "CRASH $CRASH\n">>$fileout
printf "error $error\n">>$fileout
printf "ANR $ANR\n">>$fileout
printf "NullPointer(空指针) $NullPointer\n">>$fileout
printf "ArrayIndexOutOfBounds(数据溢出) $ArrayIndexOutOfBounds\n">>$fileout
printf "ClassNotFound(类不存在) $lassNotFound\n">>$fileout
printf "ClassCast(类型转换出错) $ClassCast\n">>$fileout
printf "Arithmetic(数学运算异常) $Arithmetic\n">>$fileout
printf "IllegalArgument(方法参数异常) $IllegalArgument\n">>$fileout
printf "FileNotFound(文件未找到) $FileNotFound\n">>$fileout
printf "NumberFormat(数值转换异常) $NumberFormat\n">>$fileout
printf "StackOverflow(线程栈满) $StackOverflow\n">>$fileout
printf "OutOfMemory(内存溢出) $OutOfMemory\n">>$fileout
printf "IllegalState(无效状态异常) $IllegalState\n">>$fileout
printf "UnsatisfiedLink(未获取到so库包) $UnsatisfiedLink\n">>$fileout
printf "StringIndexOutOfBounds(字符串截取异常) $StringIndexOutOfBounds\n">>$fileout
printf "Native crash(底层崩溃) $Nativecrash\n">>$fileout
#加颜色格式
#printf "\e[31m Hello World \e[0m \n">>$fileout
}
#monkey执行之前的动作
beforemonkey
#echo monkey开始执行
monkeytest
#monkey执行之后的动作
aftermonkey
5、测试后的工作,生成报告(代码)
接下来就是pull出日志、截图、手机信息,对这些东西做处理。先把日志和手机信息写成html文件,然后重命名放到自己搭建的webserver(网站)中,把截图也放到webserver(网站)中,供别人查看。当然你事先要先搭建好网站,可以选择tomcat或jetty这种开源框架。
6、测试后续工作,发送报告(代码)
发送报告主要有两种形式,一是调用钉钉机器人发送到钉钉群里,二是发送邮件给相关人员。
钉钉消息需要包含:手机信息、错误日志类型分析、错误日志摘要、html报告的链接、截图的链接
邮件:直接把html文件和截图发过去就好了
钉钉消息效果图:
点击查看详情跳转到html网页
7、自动报bug、验证bug(代码调用接口、seleniumUI自动化)
自动报bug:就是把错误日志写到你的bug里,bug管理工具一般都是web端的,比如jira、tfs、Bugtags、禅道、Bugzilla等等,操作这些网站可以考虚用selenium写webUI自动化来实现自动报bug,也可以用代码直接调用接口来实现自动报bug,接口稳定一点。
验证bug、关闭bug:比如连续3天没有出现上次的崩溃或相同send值跑了几次没有复现,就可以调用接口或seleniumUI自动化把上次的提的bug关掉。
到此就实现了monkey的全自动化,因为monkey的脚本是自动生成的,所以不需要人工写脚本,所以才能实现全自动化。