◆版权声明:本文出自胖喵~的博客,转载必须注明出处。
转载请注明出处:http://www.cnblogs.com/by-dream/p/5048525.html
今天没上班,一大早就起来赶去搜狐网络大厦,参加一个测试技术的分享会。本打算好好的拍一个前台的照片留作纪念,结果发现这里堆了好多的快递。
进入正式话筒吧,搜狗测试人员分享的内容为PC端和Android端的精准测试;腾讯测试人员分享的是Java的hook技术。
这里我就简单的介绍一下分享的内容吧,因为涉及到两家公司的知识产权,我也不好详细的道来,因此只是简单说说,给想往这方面钻研的初学者做一个指引。
精准测试
相信大家在线上项目的话,大多都会遇到这样的场景:当发版前开发改动了一些代码,由于时间有限,我们的测试时间非常的短,因此通常会面临下面的问题:
1、较少的时间内测试的范围不足,容易发生漏测;
2、如果全部功能进行回归的话,范围太高,成本有点高‘
3、版本上线后心里没底,不知道我们的测试是否都覆盖到了修改的点。
因此我们需要引入精准测试,通过代码的变更,能够准确的定位到哪个模块会受到影响,从而执行对应的用例。最终我们要达到一个“代码的改动映射到用例”这样一个目的,实现之后每一次的代码改动,只需要关注影响到的模块,然后去执行对应的用例,这样就会非常高效的完成测试。
我以Android为例:
首先我们需要总结一个库,库里存放着多个任务,每个任务包含 用例名称、用例执行的步骤、以及用例执行过程中代码的调用关系。 当a版本更新到了b版本后,我们可以根据这两个版本之间的svn的差异,获取到代码变更的函数。然后去我们的库里去搜索该函数,当在一个任务中找到了匹配的函数后,就可以反查出我们需要执行的用例名称,从而去按照用例的执行步骤去执行。这里面一共涉及到这几方面需要我们用技术一一攻破:
1)a版本更新到了b版本后变化了什么函数?
目前大部分的代码版本控制系统使用的都是TortoiseSVN,我们可以使用svn的命令行diff命令来得到代码的变更差异,然后通过python脚本对结果进行整理,可以很容易的得到变更的函数名称,这点不用再多解释;
2)库如何行成?
首先库里面存放这是一个一个的内容,每一个内容包含用例名称、用例执行的步骤、以及用例执行过程中代码的调用关系。用例名称、用例执行的步骤可以按照正常我们写用例的方法来完成。代码的调用关系需要借助..sdk\tools\目录下的traceview.bat来获得执行用例过程中的代码调用关系,然后把它转成自己识别或者程序识别的格式。
当然由于这项技术他们也只是刚刚开始介入,会有以下一些问题暂时还没找到好的解决方案:
1、公共方法的改变意味着要去执行一遍全部的用例,然后更新函数调用关系到库;
2、当在手工执行过程中,会有一些其他的噪音函数的干扰会导致函数的调用关系无故的增多。
当然以上这两个也有解决的思路,例如第一种将公共的映射的函数提取出来,当发生改变时,只做一次用例覆盖就完成所有的更新;对于噪音函数,使用多次执行的方式排除掉。其实不止是精准测试,所有的测试都是在不断的探索和摸索中不断的进步,一点点的积累起来的。
JavaHook
腾讯分享的Java Hook技术的技术性比较强,一般的测试可能太用不到,分享的同学是专项测试的一名“女黑客”,着重于竞品数据破解,因此这方面的知识了解的比较多。
首先我想介绍一下hook的概念,hook技术也被成为钩子技术,是一种通过注入手段来修改指定函数入口点,并将其指向自己构造的中间函数的一种手段,大体分为两种形式:
1、替换型
例如A函数调用B函数,我们通过注入的手段,将A函数调用指向了我们的hook函数C函数;
2、内联行
例如A函数调用B函数,我们通过注入的手段,将A函数调用指向了我们的hook函数C函数,并且执行完C函数后,再去调用B函数,在表面看来,并没有打乱函数原有的顺序。
那么这两种都用在什么地方呢?
第一种技术,在GT的流程度测试中,我们用到了这种手段;第二种的方式和第一种方式的差别其实就是,在我们hook成功拿到我们注入的App的数据后,是否希望该App还按照原来的流程继续执行下去,如果需要让用户无感知进行注入,那么就需要这样的手段,例如干扰或者压制竞品,当然我们并不鼓励这么做。
我们首先了解下Android中一个Java代码中一个方法(函数)执行的原理:一个函数来了后,先进入Dalvik虚拟机,变成一个dvmlsNativeMethod,然后系统会判断它是Java函数还是Native函数(c层),Java函数执行的流程是走DVM解释执行,Native函数执行的流程是找到其属性nativeFunc中存放着JNI函数的地址,然后进行跳转过去。
Native函数和Java函数的区别就是一个accessFlags的属性是否为ACC_NATIVE,Java hook技术就是将Java函数的accessFlags的属性设置为ACC_NATIVE,让其变成Native函数。然后修改nativeFunc中的地址为hook函数。如果是想做到hook函数执行后再执行回之前的函数,那么需要子啊hook函数之前malloc出一块内存,记录地址,然后将原method整个memcpy过去,在hook执行之后,在memcpy回来,通过JNI的Call**Method调用原函数。
目前业内比较好的两款工具就是 Xposed Framework 和 Cydia Substrate 。前者使用比较友好,并且开源,但是仅支持Java层Native方法的hook,后者不开源,但是可以支持C/C++层的hook,但是相对用起来也是比较的geek。至于这两种工具的具体使用方法,我这里就不再做细致的介绍了,有兴趣的可以去论坛里自己去挖掘吧。
对了最后补充一句,以上所说的都是在Android的4.4版本以下(包含4.4)的手机系统中生效,目前 Android L 和 Android M 的注入技术还不是特别的成熟,因此这里没有再做介绍。
本次分享会,收获颇丰,以后如果还有类似的,我也会继续分享出来。