题记
为什么要搞 Monkey
aotoMonkey 是什么
Monkey 运行篇
Monkey 日志分析篇
Monkey 问题处理篇
Monkey 数据上报篇
Monkey 数据分析篇
写在最后
第一部分【题记】
autoMonkey是我在上一家公司自己搞的基于Android Monkey扩展的一套自动化测试框架,来源于原生的Monkey,但在此基础上扩展了很多实用的功能,此框架前后改版N次,最后基本上算是定型了并在之前的项目运行过一年的时间,效果还不错,下面也会陆陆续续讲到这些功能,希望对于大家去搞类似Monkey的框架有所帮助,更重要的是,对于大家所在的APP测试项目有实际意义的帮助。
第二部分【为什么要搞Monkey】
我们为什么要搞Monkey,其实这个问题很好回答,Monkey的引入能让我们在产品未发布之前就发现运行App过程中遇到的各种Crash和ANR,而这类的问题往往是App最严重的问题,问题发现的越早,修改问题的成本越低,而Crash率低的App上的体验明细会比那些动不动就崩溃,闪退或者无响应的App的体验高很多。在之前的项目,尤其是在灰度发布阶段(两到三轮灰度,灰度量逐渐增加),Crash率是项目组最关注的一个指标,按设备统计或者按用户统计,理想的情况我们一般要求APP在Android端低于0.3%,IOS端低于0.1%,当然了,这是我们的目标,虽然实际情况中我们统计到的比率比这个高,但想想,一个APP的DAU如果是在百万级以上,即使这么低的Crash率,反射到我们真实用户的身上,这个数字还是比较大的,所以如果能在用户发现之前尽可能多的暴露这些Crash或者ANR至关重要。
笔者曾经供职于TX,基本上无线(APP)的项目自动化第一站就是Monkey测试,当然,这里的Monkey在腾讯就不只是Google原生的那个Monkey了,这个框架太简单而且遍历的算法太随机,所以基本上都是各大项目自主去开发适合自己项目的一套Monkey框架,大致分为如下几种:
- 原生Monkey
- 重编译Monkey
- 基于Android自动化测试框架开发Monkey
原生Monkey,这个就不用多说了,具体的用法直接参考developer开发网站即可,但原生的框架缺陷实在是太多,而且还不支持activity级的黑名单功能,经常还能遇到跳到应用之外不能回来的情况,尤其是嵌入H页面越来越多的今天,所以基本上这个只是作为一个辅助的手段了。
重编译Monkey,其基本思路就是去下载Android Monkey的源码文件,然后根据自己的需要改其中对应的代码,然后重新编译成jar包,最后push到手机中运行该jar包即可。这种做法的好处有很多,你可以加入任意你想要的功能,比如截图,比如录像,比如修改原生Monkey令人诟病的遍历算法,比如发生OOM时去dump内存快照,比如优化掉快速按两次Back键就退出应用,比如网络在WiFi和3/4G之间的切换,比如按照activity级别设计白名单和黑名单等等,但缺点在于这个对于代码的功底要求极高,一般人很难完成上面所有的技术要求,而且想要设计新的遍历算法,那还需要和下面说到的第三方自动化测试框架结合开发,另外一个缺点在于因为是执行jar文件,所以只能在root的手机上才能跑起来。
基于Android自动化测试框架开发Monkey,这个就是借助于现在主流的Android端的自动化测试框架,然后结合自己项目的特点进行开发,典型的有基于Robotium和uiAutomator这两种。之前在TX的时候,笔者所在的项目就用的是基于Robotium开发的一套框架,效果也还不错,而且也还可以对于指定的部分Activity进行测试,这样针对性会好很多,因此也能提高测试的效果。
所以作为一个App测试项目的负责人或者测试人员,在性能,专项,自动化这些都还没用开展的时候,你就需要考虑如何引入Monkey到你所在的App中了,这也是我搞autoMonkey框架最根本的原因。
第三部分【autoMonkey是什么】
首先说明一点,autoMonkey框架融合了上面提到的三种框架,核心的部分就是在非root的手机上运行原生Monkey,在root的手机上运行重编译过的Monkey,而重编译过的Monkey又引入了uiautomator自动化测试框架来协助开发部分功能,具体的功能实现在这里就不一一赘述了,这里面有太多的坑,如果大家尝试自己去做的话,相信就能深深的体会到,只是提一点,这个框架里面的Monkey包含了我上述提到的绝大部分原生Monkey不支持的功能,所以在兼容原生Monkey的基础上,两者结合使用,最终也证明能够发现更多的问题。
在我入职上家公司(一家做chat的外企),发现这个app居然没有做Monkey测试,所以个人就在业余的时间开始做这块的开发。除却重新开发和编译Monkey源码的部分,整个框架都是用Python实现,陆陆续续优化或者新增功能点,前后大版本更新4,5次,到笔者最后离职的时候,整个框架核心功能基本都已经全部实现,且运行效果还是非常不错的:整个框架从开始到最后,运行大概13个月时间,累计在JIRA中提交1287个问题单,累计发现崩溃和ANR超过25000次。
autoMonkey主要分为三部分:
- Monkey的测试执行部分
- Monkey的日志分析和处理部分
- Monkey的数据上报部分
autoMonkey的主要特点:
- 全部Python实现,除插拔手机外全部都是一键自动化处理
- 灵活配置,可以同时支持多个App项目
- 利用uiAutomator优化后的随机遍历算法大大提升了App组件遍历的效率(5倍以上)
- 自动去对应的服务器(Jenkins,内部服务器)下载并安装指定分支和环境的最新版本
- 测试日志保存在手机本地,测试开始后手机可从电脑断开连接而直接连接充电器
- 自动导出Monkey的运行日志以及单个Crash/ANR的日志,并支持合并压缩
- 去重所有发现的Crash/ANR,并按照其出现的次数确定该问题的严重性/优先级
- 自动处理发现的Crash/ANR,新Bug则自动提交,已存在Bug则根据当前状态继续处理
- 丰富新提交Bug的内容,包括测试机信息,引起Crash的操作,Crash发生前的几个activity以及该Crash详细的堆栈
- 已提交但未关闭的Bug再次复现时自定添加评论和更新出现次数,已修复的Bug则重新打开
- 增加遇到OOM问题时提取内存快照的支持(需要debug版本)
- 增加自劢下载so库文件(解析native crash时需要)的支持
- 动态调整测试过程中数据网络的类型(WiFi和3G/4G之间的切换)
- 数据统计上报,包括测试版本,测试时长,activity覆盖率,activity启动数,crash次数等
- 数据分析报告,包括错误类型及占比,Crash次数及占比;可指定统计单个版本的数据用于分析
下面就针对autoMonkey框架核心功能拆开来一个个来讲其实现的过程吧。
分析之前,先放一个整个框架的流程图:
第四部分【Monkey运行篇】
之前介绍过,Monkey的运行部分兼容了原生的Monkey和重编译的Monkey,下面就从这两方面开始讲起。由于原生Monkey框架本身的局限性,因此我们需要对我们的测试设备做一些设置,简单整理如下:
- 把锁屏设置为None
- 开发中选项中设置充电保持唤醒
- 第一次安装应用时手动完成登录流程
- 对于有退出登录功能的应用,建议屏蔽掉此功能后再行测试
- 建议测试过程中全程插入耳机,以防扰民
- 如果需要保持WiFi网络畅通的话,建议安装一个叫做WiFi Automatic的软件
补充说明:
关于登录,我们可以在安装启动App之后手动完成登录之后再行开始测试,也可以用第三方的框架如uiAutomator写一个登录的jar包代替;
关于Monkey运行过程中会无意关闭了WiFi或者开启了飞行模式导致测试过程中无网络的情况,建议大家安装如上的软件,这个app支持定时或者按时间间隔打开WiFi(最短5分钟)。
再开始设计脚本之前,我们可以简单看下Monkey的这些参数:
具体每个参数的说明这里就不一一赘述了,简单说下--bugreport这个参数。强烈建议大家在跑Monkey的时候加上这个参数,一旦出现Crash或者ANR的时候,手机就会在/sdcard这个目录下生成一个txt文件,里面包含了这个Crash或者ANR相关的日志信息,包括了我们熟知的logcat,而且也有时间戳,这对我们monkey日志本身的不足是一个很大的补充。
下面开始我们框架的第一步:原生Monkey运行的Python化。
一、封装adb
创建一个adb的class,里面封装了adb所有的命令,同时呢,为了平台的扩展性更强,需要考虑Windows,Linux和Mac操作系统的兼容性。这个class大部分其实是拿来主义,我在这个基础上扩展了一些我想要的一些功能,下面会讲到:
二、Monkey运行参数的Python化
需要定义的几个参数:
- Monkey命令需要的参数,如event的间隔--throttle参数,测试app名字的-p参数(我这里因为是多个app,所以需要加入app名字的条件判断),各种异常发生后的处理参数,具体的参考Monkey命令说明。
- 日志存储路径(新建目录/sdcard/MTlog)
- 日志存储格式(版本号+测试设备序列号+分支+测试环境+测试开始时的时间戳),这些在后面处理崩溃的时候都会用得到,例如:tango_android_3.22.196195_20160227060335-4df109d22ae0af0b-O-staging2-201602280732.log
- 是否需要logcat(默认关闭,因为生成的日志实在是太大,我之前跑过一个周末的,按照error级别过滤之后的logcat日志都超过3G,解析起来也相当费劲)
设置运行的events数量(主要是为了设置测试时长,默认150万)
合并Monkey参数:
三、Monkey运行的main函数
- 是否需要自动更新测试App(设置为True时,代码就会去设置的编译服务器去下载最新的版本,可以指定版本和指定环境)
- 是否需要卸载后安装(设置为True时,则为全新安装,否者就是覆盖安装)
- 是否需要开启测试过程录屏功能
录屏功能:
视频合并功能:
由于adb的录屏功能一次只能录制最多3分钟的视频,所以需要新开一个进程持续的去录屏,并按照时间戳分别命令并保存到指定目录下,在Linux下,可以使用ffpemg来做视频合并的处理。另外,考虑到手机存储的容量问题,需要限制录屏的分辨率如480*320,实际使用发现,一分钟的视频不到5M,一小时也就300M,对于连续10几个小时的Monkey测试足以,当然麻烦一点就在于需要定时清理这些视频文件了。
补充一下,关于如何去找某个崩溃的视频文件问题。我们在运行Monkey的时候有--bugreport参数,这个参数会让app在崩溃的时候在/sdcard目录下生产一个带时间戳的txt文件,我们只需要拿这个时间戳去一堆视频中的时间戳对比即可,也挺方便的。
如果设置了自动更新测试App,则需要指定测试App的一些属性(1、App的名字,因为不同App的地址不一样而对应的地址也不一样,所以需要指定;2、编译apk存放的位置,之前公司有美国的Jenkins地址和国内的samba地址;3、App的版本,之前公司app的版本是按照字母来排序的,放到现在公司,则就是大家经常看到的2.2.1版本,2.3.0版本;4、App的环境,测试环境,预发环境,线上环境等等)。
main函数设计如下:
四、补充一,自动下载并安装app:autoInstall
基本流程如下:
代码部分如下:
这份代码没有接入Jenkins的rest api,当时都是通过urllib库访问然后正则式re去查找的,不过功能是一样的,后来接入了Jenkins的api,代码就不贴这里了,效果是一样的。
五、补充二,获取测试设备的序列号
拿到测试设备的序列号主要是写入到monkey日志中,然后解析日志名称的时候可以映射到具体的设备名称,以及设备的一些物理信息如系统版本,内存,分辨率等等,后面会讲到,这里先贴下代码,但这个映射表需要手动去创建,不过后来合并到另外一个更大的device信息表了,后面在日志分析的时候会提到。
六、补充三,下载App的同时去下载so文件
众所周知,Android端的崩溃主要是上层的java侧的崩溃以及下层的native崩溃,对于native的崩溃,我们不能直观的看到引发崩溃的具体代码而是以一个或者多个十六进制的地址出现(下图1),因此我们在遇到native的崩溃时,需要拿到这个so文件,然后利用Android NDK中的反编译工具addr2line去解析,所以autoMonkey框架后期的时候在自动下载app的同时也新起了一个线程去下载这个so文件(比较大,记得没错的话我们的app当时是200M左右,而且由于是在国外服务器的原因,所以手动的话经常失败)。
图1:native侧的崩溃
图2:下载so文件
自此,autoMonkey原生的部分就已经介绍完毕了,相对于改进的autoMonkey部分,基本上跟上面的逻辑是一样的,只是涉及到monkey.jar文件的处理以及这个jar文件支持的参数上面有些细微的不同,这里就不一一赘述了。
第五部分【Monkey日志分析篇】
autoMonkey框架会在测试手机对应的路径下生成如下的日志文件:
其中Monkey本身的日志文件才是我们重点需要去分析处理的日志,下方的都是单个崩溃或者ANR生成的日志,必要时,我们将这些日志和Monkey本身日志打包后上传到对应的问题单中即可。对于Monkey日志的解析,主要分两方面:
文件名称方面
通过文件名,我们可以得到svn版本号,测试机型号(后来改成序列号了),分支(即版本),测试包的环境(测试环境,预发环境,线上环境等)
文件内容方面
通过文件内容,我们可以得到日志中的Crash/ANR,测试时长,启动的Activity等等,下面分别阐述。
一、Crash
对于Crash和ANR的解析是分析Monkey日志最核心的部分,,我们需要知道一份日志中到底有多少个崩溃或者无响应,然后将这些发现的问题跟我们的bug系统Jira对接处理。大概的难点有两个:第一是如何解析出所有的Crash,解析后应该保存什么内容,第二是如何去重。基本思路如下:
a、读文件(Monkey本身的日志文件)
b、解析出所有的崩溃堆栈
输入:a中的Monkey日志文件
输出:一个堆栈列表crashList,列表里每个元素就是具体的堆栈信息
c、对于每个堆栈提取出一个可以代表这个crash的描述信息
输入1:b中的堆栈列表crashList中的每一个crash堆栈
输出1:一个元组,包含summary和attachFile两部分
输入2:完整的crashList
输出2:按照输入1->输出1的方法,遍历crashList,输出一个列表,该列表每个元素包含summary,attachFile和完整的堆栈三部分
d、去重
输入:c生成的新的列表
输出:最终需要的列表,其中每个元素包含四部分,summary,attachFile,次数和具体的堆栈
读文件部分,这个没什么好说的,我们在运行Monkey的时候将日志存到了手机中,解析的时候将这日志导入到pc即可,这部分其实也是自动导入的,下面将日志处理的时候会讲到,这里就先不细讲了。
Crash发生时,Monkey日志中会有日志打印,我们可以通过关键字“Crash”来发现,但我们是针对某个特定的app来跑的,所以在检索崩溃关键字的时候,需要加上App的名字,这样可以过滤掉那些非测试app的崩溃,比如系统UI的,输入法之类的,像我之前的项目,App的名字就是com.sgiggle.xxx(xxx是对应的环境,当时我们有10+的dev环境,2个staging环境和1个production环境,也基本上对应了测试环境,预发环境和生产环境),我们需要做的就是将一份日志中所有的Crash堆栈都找出来。其实Monkey日志堆栈的部分是由规律的,以“// CRASH”开头,下面的堆栈也都是以"/"开头的,最后一般是个换行符,所以主逻辑就是匹配这样的行就行了,只是需要考虑几种情况:
- bugreport生成的2行包含有时间戳的日志行,都是以app_crash开头的;
- 有的堆栈特别长(最长的超过300行),所以需要限定最大的行数,一般180足以;
- 有的时候app比较脆弱,一个堆栈还没打印完毕又来一个崩溃,所以需要限定我们截出来的堆栈信息中只包含一个崩溃,因此往下遍历的时候需要判断是否以“// CRASH”开头和"// NOT RESPONDING”开头的。
这是最早的一个版本,后来基于此,我在解析日志的时候,加入了另外两个功能:崩溃之前的几个activity和引起崩溃的事件。这两个功能都需要解析崩溃之前的日志,崩溃堆栈是"//CRASH"之后取的180行,崩溃之前的信息我则是取的这行之前的180行。引起崩溃的事件这个好办,180行日志逆序查找,得到最后一个":Current Activity",然后从中解析出具体是哪个activity名字即可;而崩溃之前的几个activity,方法基本上跟之前一样,就是按":Current Activity"查找然后解析,解析后放到一个列表中,最后按照我们需要的数量输出几个,我这里统计的是5个,所以只取倒数5个即可,如果需要更多,把这个数字改大些就行了,对应的则可能需要将倒数的行数写大一些,避免这180行里没有你想要的那么多activity,不过对于我之前的测试App来说,最后5个已经足以。
就这样,一个完整的堆栈就能拿到,遍历文件之后,该文件中所有的崩溃堆栈就全部拿到了,存到一个列表中,我们再对每个堆栈进行分析即可。下面贴出这部分的代码:
我们拿到一份日志中所有的崩溃堆栈后,需要对这些堆栈进行统一处理,目的主要由两个:一是我们需要本地去重,以减少后面和jira的交互次数;二是我们需要知道这些堆栈是否已经处理过了。按照之前的逻辑,一个堆栈里差不多几十行到180行不等,于是我想到了这样的一个方法:对于每个堆栈,我按照崩溃类型+at+崩溃的代码行来提取出一个summary出来,而这个summary又正好可以作为jira中提交问题单的描述,需要注意的几个地方:
1、崩溃的类型:从"Short Msg"中可以拿到,然后解析出即可
2、崩溃的代码行:从"Caused by"中拿到,但这个就略微复杂些,大概分两种情况,堆栈里有测试App代码的和堆栈里没有测试App代码。后者比较简单,既然没有测试App的代码,那我就取第一行,对于有测试App代码行的,那我就去取堆栈里包含有测试App代码的第一行
3、堆栈里没有测试App代码行的,这部分很大程度上是系统的一些API或者代码,这些代码的行号不像App代码那样,同样的一段代码他们在不同手机上行号很有可能就不一样,所以对于这种情况我就去掉了行号
4、一个堆栈里有可能有多个"Caused by",所以我这里加了个flag来做判断,不然的话代码只会去查找最后一个
5、对于"java.lang.IllegalStateException"这种崩溃,实际测试发现,很多时候通过上面的方法生产的summary都一样,最后仔细对比了堆栈,发现其中出问题的adapter不一样,所以最好针对这类的问题在生成summary的逻辑上再加入了adapter的解析。
6、堆栈里有该崩溃发生时候的系统日志:上面也有提到,2行以"app_crash"开头的日志,我们需要解析出完整的文件名,后续的话就可以直接从手机中自动导出这个日志并和Monkey本身日志合并压缩打包了。
考虑到上面的几种情况,最后的堆栈解析部分代码如下,每个堆栈输出解析好的summary和attachFile:
然后遍历crashList,每个crash堆栈生成的包含summary和attachFile元组放到一个list中,加上原本的堆栈,于是就得到了一个每个列表元素包含三部分内容的新的列表:
最后一步就是去重的工作。很明显,我们只需要按照summary来做对比即可,而且在对比的同时,我们可以直接得到去重后的summary的次数(可以直接用内置的count方法),于是一个全新的也是我们最后要用到的包含有我们所需要的全部信息的列表就得到了,这个列表的每个元素包含了4部分,即:崩溃的描述文件summary,具体的崩溃日志文件attachFile,该崩溃的次数和该崩溃详细的堆栈信息。去重的代码如下:
为了给大家看的更清楚,我把一份Monkye日志解析出来的信息前三部分生成了一个html文档,具体的堆栈部分也打印了下,可以直接参考:
1、前三部分(summary,次数和attachFile)
补充:python可以用pyh这个module来生成html文档,具体的说明部分可以参考官方文档:http://code.google.com/p/pyh/wiki/UserManual。关于这部分的代码,我也贴出来了,大家可以看看,以方便在别的地方也可以用得上。关于html样式部分,我们可以用css来做,更具体的这里不是重点,所以就不深了讲这块了,代码如下:
2、最后一部分(详细的堆栈信息,description)
自此,一份Monkey运行产生的日志文件中的崩溃就全部解析完毕了,一个文件到一个列表,这就是这部分的核心内容,另外需要提一下,长时间的Monkey可能会产生大容量的日志文件,如果遇到这种情况,我们需要按照一定大小分割文件后再行处理,一来是太大的文件很容易引起解析脚本的性能甚至错误,二来太大的文件也不方便上传。如下是分割大文件的代码:
既然有了分割文件,自然也有了合并文件:
二、ANR
ANR的部分跟Crash部分处理流程上差不多,我们也是按照提取summary的思路来处理ANR的,详细的就不一一细说了,只说和Crash不同的几个地方:
1、ANR的堆栈一般比较长,我之前取的是200行,如果不够的话,可以取更长的
2、出现ANR的activity一般在ANR堆栈的第一行,原因可能在第二行,以“Reason”开头的,分别提取处理后生成summary即可
3、reason部分可能会有很长,jira中提交问题单的时候summary最长是128个字符,所以如果生成的summary长度大于这个数的话,会有截断,不过这部分我交由后面统一处理了。
下面就分别把日志解析ANR和ANR堆栈处理两部分的日志代码贴下面,至于去重部分就和Crash完全一样了:
日志解析ANR:
解析ANR堆栈生成summary:
就这样,一份日志中最为关键和重要的Crash和ANR就全部解析完毕了,测试时长和activity的覆盖率我会在数据上报部分再行讲解。从一份Monkey日志中,我们得到了两个列表,里面有我们需要的Crash和ANR的所有信息,接下来我们就需要跟我们的bug系统对接了。
第六部分【Monkey问题处理篇】
一份生成好的日志经过上面部分的处理之后变成了两个列表,这部分的重点就是如何处理这两个列表了,即和Bug系统(之前公司用的是Jira)的交互了,主要步骤是:
1、Jira模块:连接Jira并封装一些rest api
2、日志导出模块:从手机中导出Monkey日志,崩溃日志
3、日志分析模块:Crash处理,ANR处理
4、崩溃处理模块:新问题时提交问题单,已有问题单更新状态
5、数据汇总模块:测试手机,activity覆盖,测试时长,崩溃次数累计,提交问题单号等
流程图如下:
一、Jira模块(jira_tango.py)
Jira有封装好的python版本的rest api,所以需要先安装jira,安装和更详细的api使用说明可以直接参考网址:http://jira.readthedocs.io/en/master/
下面贴几个我写的几个方法:
1、获取Jira中提交的崩溃bugList
备注:笔者后来又让同事也帮忙跑Monkey,所以查找所有崩溃的bug列表时需要加上这位同事的jira账号;另外就是search_issue这个api默认只返回50条数据,所以需要制定maxResult参数,但上限是1000条,由于项目后期我在Jira中提交的崩溃bug已经超过1000个,所以就按时间段分开查询,然后合并即可。
2、查看summary是否已经在Jira中存在
3、获取指定Bug的状态status和resolution
二、日志导出模块(pullMonkeyLog.py)
主要处理Monkey日志和崩溃日志两部分,这两部分其实是一样的而且都存在手机中,我们只需要告诉脚本日志存放的位置以及文件的名称即可。对于崩溃日志,我们之前已经讲过了,在解析日志的时候已经得到了完整的文件名,而这种日志都是存在手机的/sdcard目录下,所以就剩下Monkey的日志了。
前面也提到,我们在运行Monkey的时候,日志的命名中已经加入了时间戳的概念,所以一般情况下我只需要去取最新的一份日志即可:
1、按照最新的时间戳解析出文件名
备注:日志从手机导出到PC端是需要指定一个PC目录的,默认是脚本的当前目录,但也支持手动设置一个本地的目录,不过需要注意的是,Windows和Mac下路径的设置是完全不同的。
2、自动导出日志:
备注:Windows下路径的写法是"\\",而Linux和Mac上是"/",不过我们都可以用os.path.sep来替代。
3、日志(合并)压缩
为了上传方便,需要将日志压缩,如果有崩溃日志,更合理的情况是将这两部分日志合并压缩到一个压缩文件中,最早我在Mac上用的是tar模块,后来切换到Windows上用的是zipfile模块。
备注:Monkey的日志我存的是.log文件,崩溃日志这个是.txt文件。
三、日志分析模块
参考上一章节。
四、崩溃处理模块
这部分主要就是跟Jira的对接部分了,基本的流程如下:
1、获取Jira中提交的所有Monkey Crash的Bug列表
2、检查新发现的问题是否已经存在,存在则返回bugID
3、如不存在,则新提交问题单
新提交一个问题单最重要的一点是把提交问题单所需要填写的字段都给找出对应的方法并赋值,大家需要明白的一点是,每个Jira项目需要填写的内容是完全不一样的,而且很多项目都有自定义的一些字段,所以除了通用的一些字段能直接使用之外,其他的字段(一般都是以customfield_xxx)都需要通过查询api来获取,具体的方法就是找到该Jira项目中存在的一个问题单然后去查询即可,查询的样式是jira地址/rest/api/2/bugID,例如我之前的项目就是:http://jira.tango.corp/rest/api/2/issue/ABC-123,拿到字段之后,我们再对他们进行相应的赋值,最后提交即可。
备注:
- 我这里最早是针对Native的崩溃做了单独处理的,所以先做了个判断,后续的话其实全部合并到一起了。大家也能看到,这里面有大量的customfield字段,这些都是Jira的管理员自定义的,每个项目完全都是不一样的。
- 问题单的描述也就是我们之前处理日志生成的summary部分,另外加上了一个标志"Android-Crash",测试App的名字,发生问题的机型(通过序列号映射过来的)
- 问题单的详细描述部分,这个取的就是我们处理完的每个崩溃中详细的堆栈部分,里面包含了最近的几个activity,引起问题的事件序列和错误的堆栈,但我在这个基础上还加了一个测试手机的配置信息,比如内存,系统版本,分辨率等等,这个也是通过映射得来的,这个表需要人工添加。
然后把这些内容分字段分别整合,最后添加到我们之前的问题单详细描述部分,这样,我们在Jira中看到我们提交的问题单就包含了四部分,即【测试手机信息】,【崩溃之前的几个Activity】,【引起崩溃的事件】和【详细的堆栈】,这样对开发来说,也能更好的了解问题发生的原因,也让他们能更好的去分析和解决问题。
- 另外补充一个小技巧,详细描述部分,在堆栈的前后分别加上"{noformat}",整个堆栈就能被很好的展示出来,可以局部滑动查看
4、若存在,则检查根据其问题单号查找当前状态
5、当前状态为非关闭时,添加评论并更新问题出现次数
非关闭状态的Bug处理:
更新Bug出现次数:
由于autoMonkey框架前期没有加入次数统计的功能,所以最早提交的问题单没有这个字段,也就导致了后来需要兼容这部分的问题单,逻辑上也不难,主要也就是判断心焦的Time这个关键字是否在summary中存在,如果不存在,则先添加这个字段并把之前的次数都初始化为1次,然后加上现在的次数;如果存在这个字段,则直接更新次数即可。
兼容不存在次数字段的问题单:
存在次数字段的问题单:
6、当前状态为关闭时,则继续查看其关闭问题单时的方案(resolution),若因为已解决或者不复现等原因关闭时,重新打开问题单并添加评论和更新出现次数,同时本地导出Monkey和崩溃日志进行压缩打包,否者不进行处理(最早是放到本地的一个won‘t fix的列表中的,后来也都不需要了)
Bug状态为已关闭时:
Reopen已关闭的Bug:
备注:Jira中改变Bug状态是通过transition_issue来进行的,需要找到状态转换之后的值并且符合Bug流转的流程才行,比如已关闭的问题单,我们可以重新打开,但不能解决
再补充一点:由于之前公司的App拆分成2个独立的App,所以后来autoMonkey框架为了兼容两个App的日志处理,统一加入了从属于哪个App的逻辑,如果只在某个App出现,则在summary中只有该App的名字,但如果两者都有,则两者都加上。
同样的,也需要兼容最早没有这个字段的问题单:
自此,从日志中发现的崩溃或者ANR就处理完毕了,整个过程都基本上不需要人为再干预了,但这里面有几个问题,也请大家注意:
1、提交问题单时无法自动添加附件的问题:这应该是jira rest api的问题,使用add_attachment一直报错,所以这块我都是代码自动合并压缩之后手动上传的;
2、关于提交问题单分配的问题:个人建议所有新提交的问题单都先分配给自己,检查下没有问题之后再分配给对应的开发;
3、一个良好的Jira问题单处理流程真的很重要;
4、如果Jira项目是中文的,这块需要考虑中文字符的问题,如果是这样,建议通过python3来搞,autoMonkey最早是在2.7的版本做的,后来移植到现在的App测试项目上,在中文处理这块遇到了很多编码的问题,不过不用着急,慢慢处理就是了。下面贴两个中文的代码:
新提交问题单:
根据不同Bug状态处理:
第七部分【Monkey数据上报篇】
发现的问题都已经在Jira中处理完毕了,但我们还可以做得更多一些,那就是做一些数据统计的工作,例如测试机型,测试时长,测试版本,启动activity次数,发现的问题单号,新提交问题单号,测试执行次数以及累计崩溃次数等等。做法也比较简单,现在Jira中创建一个任务单,按照上面需要统计的字段做个模板然后放到这个任务单的description中,每次处理完Crash或者ANR之后,再去处理这些字段,拿到数据之后,更新Jira中这个任务单即可。
数据统计的字段包括:
统计启动Activity的次数:
Monkey日志中启动activity都有日志的,按照"// Allowing start of Intent"来查找即可,查找完了按照惯例,需要做去重然后统计的事情:
新的Monkey也可以按照"Current Acticity"来查找:
最后,按照activity级别统计次数以及占比:
统计单次测试执行时长:
时间的处理是按照日志中最后一次"calendar_time"的时间减去第一次的时间,然后换算成小时和分,最后累计处理即可。
就这样,当一个版本测试结束的时候,Jira中的这个任务单就会累计更新了N次,最后稍微整理下,就可以当做这个版本的Monkey测试报告发给项目组的人员了。当然,除了这个,我们其实还可以分析的更深入一些,比如单个版本甚至整个App项目的问题单分析,这部分就留到下面再说了。注意一点的是,我们是每个版本独自创建在Jira中创建了一个任务单来做数据的统计的,所以每个版本需要创建这么一个而且不能弄错了,不然数据就不准确了,我专门写了个变量来存储这些任务单,而且也不需要我每次都去改配置,比如下面的"O_tango",这完全是当前的版本+测试App拼接的,所以主逻辑我压根就不需要改动,仅仅需要在新创建一个任务单的时候,更新下这个表即可,当然,最好的方式还是用数据库来做,但目前对于这个框架来说,这种方式也基本上够用了,所以就没再继续写数据库的东西了:
第八部分【Monkey数据分析篇】
我在这里主要针对我提交在Jira中的问题单按照崩溃类型做了筛选,并统计该类型下提交问题单的个数和崩溃的次数,以及对应到所有纳入统计数据中的占比。大概分两部分:先按照我们之前的查询条件导出提交到Jira中所有的Monkey测试的Bug并按照需要的字段存到一个csv文件,然后用excel做一个我们想要输出的一个模块(涉及到数据的部分必须用公式来做),替换下新的数据之后对应的数字都会自动更新了。
一、Jira问题单处理并导出到csv文件
主要统计了问题单号,描述summary,错误类型,问题出现次数,当前状态,解决方案,提交人,分配人,提交日期等字段,上面的字段除了错误类型和次数之外,其他的都能通过rest api直接或者间接拿到,所以这里简单写下这两部分的。
1、错误类型
解析summary中“at”之前的部分,注意需要考虑ANR和Native这两种特殊的情况:
2、问题单出现的次数:
解析summary中“Time”之前的部分:
最后将上面的所有字段一一存下来,最后写入到一个csv文件中:
二、生成深入统计的数据报告
将上面生成的新的数据替换掉之前的数据,由于这都用的是公式,所以数据就会自动更新了,指定版本的话,则需要在问题单导出的时候设置查询条件,比如时间或者版本。就这样,整个App项目以及单个版本的数据分析报告就出来了。
1、测试App项目的数据分析报告:
2、测试App单个版本(一)的数据分析:
3、测试App单个版本(二)的数据分析:
第九部分【写在最后】
这个框架(姑且叫框架吧)都是我一个人慢慢码出来的,前后更新了5,6版,很多功能都是一步步慢慢添加完善起来的,正好也是对我自学Python效果的一个检验吧,说实话,我的代码功底其实很弱,正是边学边用于项目的实践让我对Python有了一个更深刻也更检验实际效果的理解,当然,这里面还有太多的东西值得我们去深入学习和挖掘,就像我今年年初的时候出去找工作,曾经有一个面试官问我这个框架有哪些缺点,是的,这个框架也有很多问题,不知道看过的各位有什么想法,有的话可以找我或者留言交流吧。
写在最后的最后
本着服务于更多APP测试的想法,如果大家所在的APP测试有需要我协助帮忙测试的话,可以私下和我联系,相信我,这个框架能发现很多各位手工或者自动化发现不了的诸多APP Crash问题,而且不需要各位提供任何源码,使用任意官方渠道的安装包即可。之前一个朋友告知了我他的APP的名字,于是在应用宝中下载安装后运行了10个小时,在我的测试机上发现了4个累计8次的APP Crash问题,我用脚本已经解析出来了,如下:
目前为尝试阶段,不收取任何费用,完成后会提供相应的错误日志,后期的话如果效果好,考虑到设备损耗问题,可能会考虑收费,请各位知晓。
文字略多,后续会把大部分的代码开源,也借此文缅怀我的大Tango~
原文地址:https://www.cnblogs.com/xiaowenshu/p/10390412.html