第二部分,原理和方法。我们刚才也给大家普及了基础的东西,这部分的training set,都是来自于实际中编写的代码或者是样例,是作为Bug预防的第一代原形,相对来说比较简单,只用了一个圈复杂度,知道圈复杂度的同学举一下手,为什么可以作为预测Bug出现概率的重要指标?就是圈复杂度会根据你写的代码,里面有多少分支,走多少流程,跟圈复杂度是对照的。一个函数里面,如果圈复杂度,工业级别上的,好比军工的软件,一般检测出来不超过7,或者更严格的,代码复杂度不能超过5,当圈复杂度越高的时候,就证明写的函数体越来越长,但是如果在5和7以内,大概40行左右,超过7以上,到20了,代码行数就有可能变成几千行了,几千行的函数,无论是让原来的开发,还是接手的新开发来去做这个事情,都变得很难维护。既然是我们能知道圈复杂度有这样的功能,我们可以用圈复杂度来预测提测代码之后,去扫一下圈复杂度,看是不是在合理的范围内之内,如果不在合理的范围之内,可能会有一定的概率出现Bug。
这个图里面介绍了学术界应用,把加入的代码出现的Bug解决掉,做了一个样本,没有修Bug之前代码是怎么写的,修完Bug之后代码又是如何写的。
现场视频(中)
这是基于Bug定位出现的第二个原形,用来预测Bug缺陷。从第一个原形到第二个原形,中间已经多了很多步骤,首先需要有一个dataset。第二是前面说的学术界的获取dataset的方法。第三是用人工自然语言的去处理,不用java管理的,或者不跟javaBug关联的,但是有很多开发去直接写,用英文也好或者用中文注释也好,会说某某个问题,这是一般开发都会做的。第三个是获取样本的方法。将来可能出现Bug的因素有哪些,这是这些因素做了排序和处理,做Bug定位或者预测的时候,首先得知道哪个指标应该占什么样的比例,用刚才的方法,就去不断调整各种指标占的比例,然后根据所占的这些比例多少,判断实际得到的和最终现实发生的真实的Bug匹配度,在人工智能中有一个专业名词是召回率,来看最终的结果,这是属于第二代的原形。在这个原形里面,有一个test的样本,大部分是使用变异测试来做的。
这是基于java的,参考各种因素和指标,能得到一些样例结果的展示。每种定位技术,得到的能定位的结果差异也是有很多的,如果大家想去看具体的实现,在这个底下有一个连接,把种种技术,包括方法,源码,结果,都生成一个统计结果,可以到里面看具体的执行情况是什么样的。
这是堆栈,现在的堆栈抛出,一般情况下,无论是前端也好,还是后端也好,都要求封装。Exception,堆栈有多个方法,异常的会提示说属于什么样的异常,既有基于系统级别的,也有中间件定义的,也有用户行为定义出来的,这个时候我们不能单纯的说用它做缺陷预防,我们首先要把三个分层,不能直接简单拿过来用,基于堆栈去预测这种情况,这样就会更加准确。这个里面会告诉你某一个类,某一个方法,底下具体是哪一行到哪一行,我们基于热点覆盖的时候经常会提一个概念,拿到修改的行,通过修改的行去匹配,这个行的代码就会明确的告诉你我在这行抛了,开发去解决问题的时候,就有经验的开发,会做一件事情,永远去看0或者1的,不去看后面的,后面再抛出来的跟现在是完全不一样的。既然开发都能够通过这个来做,我们可以转化为一个缺陷预防,或者是判断的技术手段,这个时候我们就可以去针对这些抛出来的Exception,再做一个排名,需要收集线上所有的日志里面,把所有日志里面无论这类也好,还是这个方法也好,只要在里面出现一次,我将排名就加“1”,会首先看全局的哪类哪个方法,即使行数不一样,我要统计到这个方法底下服务端的排名情况。
我刚才所说的都是为如何建立我的缺陷预防的指标的参考依据,大家可以看到这些指标,比如有多少个链路的调用,总共有多少函数处在这个破抛出来的这些堆栈的异常相关信息,十前面的ST作为基础数据,我们发现只是用基础数据去预测Bug出现Stack Trace概率并不是很准确,到底出现Bug的概率是什么样的,我们相当于做了一个类似于加权平均,或者统计学里面应该叫取一个均值,把参数做一个综合,举个简单的例子,如果这个项目中只有两个文件,如果抛出来一个堆栈异常,两个类里面有多少个,和我有10个文件,但是每个类里面的代码行数对应的行数不同,如果想全面的了解到Bug出现的概率,就不能简单的以其中一个指标作为参考。做了一个组合之后,就相当于把出现Bug的概率和情况做了一个更加详细的指标定义。我们有了这个指标的定义,就更容易预测Bug出现的概率。
这是堆栈信息人工智能预测的模型,把Stack Trace和错误的代码进行了关联,做了一个提取和模型的建立,并且自动的把它打标,第二个阶段,我已经有了线上这么多出现的异常,我们新来一个,能不能直接定位到某一类某一行的方法上。
济南网站建设公司为什么要做这个事情?现在测试不是左移就是右移,对于我们来说,跟开发合作的时候,他认为比较理想的测试是说不用给那么多步骤,不用那么多方法,能不能写一个单元测试,能不能直接告诉我问题出在哪儿。有很多的方法是希望测试做到这样的,并不是说测试做不到,测试也是可以做到的,但是需要很多的工具,包括历史数据的积累才能做到。而且有很多的情况,测试对于场景,包括业务了解得更多,这里只写了模块的一小部分,如果把测试的这些反馈到开发身上,就可以做到这一点。
这是第三代的技术,会把静态分析和动态分析做整合,把代码的覆盖率,方法的覆盖率,包括分支的覆盖率,统一放到矩阵里面,在这个矩阵相对应的,可以认为原生的第一代是一维的,只有一个东西帮我们做判定,这个是一个二维的,到了第三代其实是做了更多维度的,但是这个维度里面既包含了静态,又把动态的也放进来了,同时也把覆盖的行这些东西也都做到统一的PageRank Matrix里,从多个角度去看能不能预测这个Bug出现的概率。
最终,我们会得到一个Rank List,我们统一做各种排序,再去看预测Bug出现的概率就会比之前更加准确。
还有一个是基于行为的,也是最近刚刚出现的用来定位Bug的,就不展开描述了。
然后我们说一下怎么应用,程序频谱是一种有效的Bug定位的方法,作为卡壳的时候,首先不能单纯的说以指标来衡量,需要把它作为综合的指标去看整体的提测质量之后,就会发现之间是有正相关的,或者呈线性的数据的指标,代码写得越烂,出现的Bug概率就会越高,这是毋庸置疑的。第二,Stack Trace对于Crash的定位是很有效的,现在手机经常运行着的时候就不动的,或者响应比较慢,我们去拿到堆栈的错误异常,上报上来,这个时候对于去定位这些异常是很有效的,用它来提高安卓端的响应,包括出现什么样的错误,这是十分有效的手段。第三,错误的样本集目前仍然不够大,刚才说的三种方式,还漏掉很多没有按照规范和固定操作制度,中间有很多开发没有按照这个去做,有一个叫全样本,这也是息息相关的因素。还有一个,算法的多样性,我们用静态和动态的调用,里面的算法也是多样性的,目前有20多个算法,算法也决定了预测Bug出现概率的重要参考因素。很显然,第一代的不如第二代的,第二代的不如第三代的,但是这些迭代的版本、方法多了之后,原来简单的算法也不适应了,每增加一个因素,或者每增加一个参考的因子,模型也要做相对应的处理,这样才能预测Bug出现的情况。
现场视频(下)
通过这些Bug定位的技术和方法,我们拿到最直接、最有效的方式。把它作为实地落地的情况,通过这些能够对我的企业产生直接收益,一般情况下,前面分析了那么多,但是这些东西都不能落地,或者都不能提高协同的效率,推广和应用是很困难的,我们通过它可以做到的有这四个场景,能够提高大家的效率,辅助开发来定位Bug。阿里内部有一个可视化的质量分,分了四个维度,第一是圈复杂度,第二是面向对象的指标,第三个我忘记了,每个指标里面都有因子,每个方面给一个权重,提测完代码之后进行开发,跟代码的质量分是不是有直接关联。 指标定义好,就可以发现问题,指标定义不好就会出笑话。
Bug的重复检测,如果我们做交叉,或者是比较大的,比如我们使用外包,免费的从网上公开共测的东西,他们提过的Bug之后,我们也可以去做去重,来决定将来判定一个重要的指标。Bug的自动assign,每个开发提交的,根据这个场景涉及到的case,或者提交分支版本,可以将Bug和这个产生者直接做一个关联,出现了Bug就可以不需要判定是哪个开发要做的事情,
济南网页设计可以告诉是这个东西出了问题。然后是case的等级分类,相信大家在做第四个的时候,都应该会做,如果不做case的等级分类,就是测试连入门都没有做到。为什么要把它提出来?因为我们发现现在有很多的工具也可以帮我们生成单元测试的代码,但是这些单元测试的代码和这个之间并没有作为强关联。大家都知道“8020”法则,80%的Bug来自于20%的代码,我们所有case也不应该在同一个级别,可以针对这个理论,对这些20%的代码做case等级的分类。迭代的版本越多,开发和测试不断在维护自己自动化的脚本,包括单元测试的脚本,这些东西会慢慢的越积越多,这个时候之前第一个版本跑了10分钟就能跑完,但是运行了半年,或者是一年以上,这个项目没有死,你会发现测试用例一直往上堆,之前跑10分钟,半个小时就能跑完,现在是用空间换时间看case执行的情况。我们除了用空间换时间之外,还可以用等级分类的方法把这些case标志出来,可以用少一些的空间,或者是少一些的时间。
转载:Testin