之前看到有人在论坛里面问 monkey 的执行,我决定不按照前言中的顺序写了,大家可以各取所需。本篇文章与 Monkey 有关,但又不局限于此。我曾经尝试用 Monkey 来做 crash 的收集。

  1. Monkey 的执行
  2. Log 的分析
  3. Crash 的采集
  4. 思考和讨论

Monkey 的执行


当我刚开始接触移动互联网的时候,到处找关于 Monkey 的文档看,每篇文章都说 Monkey 很简单,就一条命令,然后就是对各种参数的说明。
后面等我实践的时候,发现用好 Monkey 不是件容易的事情。如果仅仅是执行这条命令,当然很容易。一般情况下,跑 Monkey 的同时,获取其 Logcat。对 Logcat 的日志进行分析能发现很多问题。
请看我的实现:

#encoding:utf-8
import os
import time
import re

###############################################################
#########                  Monkey测试                  #########
#########                作者:Anderson 糖果            #########
#########                版本  V1.0.1                  #########
#########                时间:2015.04.25               #########
################################################################

packageName="com.XXXX.app"
logdir=r"d:\jenkins"
remote_path=r"\\10.21.101.100\build\android"

os.system('adb shell cat /system/build.prop >D:\jenkins\phone.text')

f = r"D:\jenkins\phone.text" 

def getcmd(cmd):
    f = open(cmd,"r") 
    lines = f.readlines()
    for line in lines:

        line=line.split('=')
        if (line[0]=='ro.build.version.release'):
            version = line[1]
        if (line[0]=='ro.product.model'):
            model = line[1]
        if (line[0]=='ro.product.brand'):
            brand = line[1]
    return version,model,brand


version,model,brand=getcmd(f)

print version,model,brand
os.remove(f)

#print "使用Logcat清空Phone中log"
os.popen("adb logcat -c")

#print"暂停2秒..."
print "wait"
time.sleep(2)

now1 = time.strftime('%Y-%m-%d-%H_%M_%S', time.localtime(time.time()))

#print"开始执行Monkey命令"
monkeylogname=logdir+"\\"+now1+"monkey.log"
print monkeylogname
cmd="adb shell monkey -p com.XXXX -s 500 --ignore-timeouts --monitor-native-crashes -v -v 10000 >>%s" %(monkeylogname)
os.popen(cmd)   

#print"手机截屏"
os.popen("adb shell screencap -p /sdcard/monkey_run.png")

#print"拷贝截屏图片至电脑"
cmd1="adb pull /sdcard/monkey_run.png %s" %(logdir)
os.popen(cmd1)
print "gai ming"
oldname=logdir+"\\"+r"monkey_run.png"
if (os.path.exists(oldname)):
    print "file is exist"
else:
    print "file isn't exist"
newname=logdir+"\\"+now1+r"monkey.png"
os.rename(oldname, newname)

#print"使用Logcat导出日志"

logcatname=logdir+"\\"+now1+r"logcat.log"
cmd2="adb logcat -d >%s" %(logcatname)
os.popen(cmd2)

#print"导出traces文件"

tracesname=logdir+"\\"+now1+r"traces.log"
cmd3="adb shell cat /data/anr/traces.txt>%s" %(tracesname)
os.popen(cmd3)

Log 的分析


当时在网上找文档时,都是说在 Monkey 的 log 里面找 “FC”,“ANR”。我另劈蹊径,对 Logcat 日志进行解析。

######################
#获取error
######################

NullPointer="java.lang.NullPointerException"
IllegalState="java.lang.IllegalStateException"
IllegalArgument="java.lang.IllegalArgumentException"
ArrayIndexOutOfBounds="java.lang.ArrayIndexOutOfBoundsException"
RuntimeException="java.lang.RuntimeException"
SecurityException="java.lang.SecurityException"

def geterror():
    f = open(logcatname,"r") 
    lines = f.readlines()
    errfile="%s\error.log" %(remote_path)
    if (os.path.exists(errfile)):
        os.remove(errfile)
    fr = open(errfile,"a")
    fr.write(version)
    fr.write("\n")
    fr.write(model)
    fr.write("\n")
    fr.write(brand)
    fr.write("\n")
    fr.write(now1)
    fr.write("\n")

    count=0
    for line in lines:
    if ( re.findall(NullPointer,line) or re.findall(IllegalState,line) or re.findall(IllegalArgument,line) or re.findall(ArrayIndexOutOfBounds,line) or re.findall(RuntimeException,line) or re.findall(SecurityException,line) ):
            a=lines.index(line)
            count +=1
            for var in range(a,a+22):
                print lines[var]
                fr.write(lines[var])
            fr.write("\n")
    f.close()
    fr.close()
    return count


number=geterror()
print number

看到的结果是这样子的:

所有的 crash 都在这个 log 里面展现,一目了然,而且放到了共享目录,开发可以直接访问。其实这里面还统计了出现闪退的次数,为了统计次数,没有去重。(这个脚本还是写得比较粗糙,但是能达到要求了,有兴趣的可以在上面继续优化。)

Crash 的采集


这种方式是能采集到一些闪退,但这远远不够。因为客户那边出现闪退,你是没有现场的。有没有一种方法来监控这些闪退。不管是测试这边还是客户那边,只要有 crash,就会向服务器发请求,将 crash 的具体信息记录在数据库里面。
例如:

后面有跟这个系统的作者有交流,他是重写了线程监控 UncaughtExceptionHandler。他说可以把接口开放给我,我目前还没开始研究。等有了结果,再来分享。

思考和讨论


  1. IOS 上的 crash 如何监控?
  2. 跑 Monkey 时,如何屏幕解锁?有登录咋办? 在登录以后跑,它退出了咋办?
  3. 跑 Monkey 时,怎么避免它将 wifi 或网络关掉?
  4. 开发如何面对这些你捕获的 crash log? (我们的开发有一大堆理由说看不懂,解不了)
  5. 有没有更好的 crash 捕获机制?你们是如何做的?

PS: 最近想挪窝,base 上海,求收留。可以联系恒温和在群里找糖果


↙↙↙阅读原文可查看相关链接,并与作者交流