基于插桩技术的安卓应用软件自动化测试方法

文档序号:6546846阅读:321来源:国知局
基于插桩技术的安卓应用软件自动化测试方法
【专利摘要】本发明涉及一种基于插桩技术的安卓应用软件自动化测试方法,包括以下步骤:步骤一、反编译被测试安卓应用软件,生成资源文件与smali源文件;步骤二、编写探针代码,在smali源文件中插入探针代码,获得修改后的smali文件;步骤三、对步骤二获得的smali文件进行重新编译,生成用于测试的应用软件,采用该应用软件完成被测试安卓应用软件的测试。与现有技术相比,本发明采用插桩技术编写探针代码并实现探针代码的插入,最后完成安卓应用软件的测试,具有方法简便、测试可靠等优点。
【专利说明】基于插粧技术的安卓应用软件自动化测试方法
【技术领域】
[0001]本发明涉及一种软件测试方法,尤其是涉及一种基于插桩技术的安卓应用软件自动化测试方法。
【背景技术】
[0002]一、当前安卓应用自动化测试的难点
[0003]当前安卓应用软件的自动化测试一般采用robotium框架编写自动化测试用例。通过IObotium框架,自动化测试用例在执行时,可以获得被测试安卓应用软件的UI信息,也可以模拟用户进行按键或触屏操作,从而可以对被测试安卓应用软件的逻辑进行测试。
[0004]但是,由于安卓系统安全性的限制,robotium框架在下面的自动化测试场景中存在问题:
[0005]1.测试用例要求对被测试安卓应用发出的Intent进行检查,以确认被测试安卓应用各模块内部之间的耦合、被测试安卓应用与安卓系统之间的耦合、被测试安卓应用与其他应用之间的耦合是否正常。
[0006]2.对很多与后台服务有关的安卓应用进行自动化测试时,为降低被测试安卓应用与服务器之间的耦合,使测试的软件逻辑清晰可控,测试用例要求对服务器进行Mock。
[0007]3.对使用了 GoogleMap服务的安卓应用进行自动化测试时,测试用例要求对被测试安卓应用的Google MAP(V2)的相关功能数据进行检查,以确认被测试安卓应用的Google Map的相关软件逻辑正常。由于Google Map (V2)是作为第三方库的形式被测试软件集成,而且Google Map (v2)并不支持自动化测试,所以在robotium框架下无法对GoogleMap (v2)进行自动化测试。
[0008]二、程序插桩技术
[0009]程序插桩技术最早是由J.C.Huang教授提出的,它是在保证被测程序原有逻辑完整性的基础上在程序中插入一些探针(又称为“探测仪”),通过探针的执行并抛出程序运行的特征数据,通过对这些数据的分析,可以获得程序的控制流和数据流信息,从而实现测试目的的方法。
[0010]三、安卓应用反编译及smali汇编
[0011]安卓应用均采用Java开发,运行在android dalvik java虚拟机之上,可以使用工具将安卓应用进行反编译,得到资源文件和smali语言的源文件,也可以使用工具将反编译得到资源文件和smali语言的源文件再次编译打包,生成安卓应用。
[0012]smali是android dalvik java虚拟机反编译后的采用的一种类Jasmin语法的汇编语目,它是Java语目的指令级描述,与Java语目有 对应关系。其特点是:
[0013](I)文件命名
[0014]在每个smali源文件中只能定义一个类,源文件的名称与类的名称相同,源文件的扩展名为smal i,源文件所在的目录为类的包名。例如:类com.droidbox.sandbox.DroidboxGoogleMapffrapper 所对应的源文件为 com\droidbox\sandbox\DroidboxGoogleMapWrapper.smali。
[0015]⑵数据类型
[0016]smali语言中,有两种主要的类型:基本数据类型和复杂类型。复杂类型又分为对象类型和数组。
[0017]基本数据类型
[0018]smali语言中的基本数据类型与Java中的基本数据类型相同,采用一个字母表示,与Java中类型对应关系如下表所示:
[0019]Smali 类
[0020]型VZBSCIJFD
[0021]对应Java
[0022]类型 void boolean byte short char int long float double
[0023]对象类型
[0024]smali语言中的对象类型即为Java中的类,采用的表示形式为:Lpackage/name/ClassName$InnerClassName ;
[0025]例如:Lcom/droidbox/sandbox/DroidboxGoogleMapWrapper$MapHeIper ;
[0026]它等同于Java语言中的 com.droidbox.sandbox.DroidboxGoogleMapffrapper.MapHelper0
[0027]数组
[0028]smali语言中的数组类型即为Java中的数组,采用的表达形式为:[DataType。'['的个数表示数组的维度。例如:'[I '等同于Java语言中的“int[]”,' [[Ljava/lang/String/ 等同于 Java 语言中的 “ java.lang.String[][] ”。
[0029]⑶寄存器
[0030]在Dalvik Java虚拟机中,所有的数据(包括基本数据类型的数据、对象、数组类型的数据)必须保存在寄存器中才可以使用,执行。
[0031]在Smali语言中,有两类寄存器用于保存数据。一类是用于保存局部变量的变量寄存器,采用字母V表示,用数字索引来区分。另一类是函数内用于保存传入参数的参数寄存器,采用字母P表示,使用数字索引来区分。
[0032](4)函数及传参
[0033]在smali语言中,函数采用的表示形式为:
[0034]Lpackage/name/ClassName ;->Method (ParameterTypeList) RetumType。
[0035]例如:Ljava/util/ArrayList ;->get (I) Ljava/lang/0b ject ;
[0036]在这个例子中,“Ljava/util/ArrayList ; ”表示函数所属的类为java.util.ArrayList0 " get"为函数的名称。"I"为参数类型列表,表示参数只有一个,为int类型。"Ljava/lang/Object ;"表示函数的返回值为 java.lang.0bject 类型。
[0037]在smali语言中,当一个函数被调用的时候,采用寄存器传递函数参数,而且函数的参数被置于寄存器列表的最后N个寄存器中(N为函数参数的个数;通常,每个寄存器保存一个参数)。相对于静态函数,由于非静态函数存在隐藏的this参数,所以非静态函数在进行参数传递时实际传送的参数个数为N+1,而且参数列表中的第一个参数总是该函数所属的对象。[0038]例如,非静态方法LMyObject ;_>calIMe (II) V有2个整型参数,另外还有一个隐含的LMyObject ;类型的this参数,所以此函数被调用时,共使用了 3个寄存器来传递参数,而且第一个寄存器保存的是该函数所属的对象。
[0039](5)指令与伪指令
[0040]与常见汇编语言一样,在smali语言中,也存在伪指令和指令。伪指令用于指示编译工具如何进行编译,主要功能有声明类名、声明父类、声明接口、声明引用类、声明函数、声明参数、声明变量等。指令则用于指示Dalvik java虚拟机的执行,主要包括寄存器操作指令,跳转指令,函数调用指令,函数返回指令,类型强制转换指令、对象创建指令、进程同步区块指令。
[0041]Smali语言的函数调用指令的语法格式为:ins {RegList}, Method。
[0042]Ins表示具体的函数调用指令。在Smali语言中,invoke-virtual,invoke-virtual/range, invoke-direct, invoke-direct/range 为非静态函数调用指令;invoke-static, invoke-static/range 为静态函数调用指令。
[0043]RegList表示函数调用时用于传递函数参数的寄存器列表。寄存器名称之间采用逗号分隔。
[0044]Method表示函数的全称,包括函数所属的类名,函数的名称(在类内的名称),函数的参数列表,函数的返回类型。
[0045]例如:invoke-virtual{v2,vl}, Ljava/util/ArrayList ;->get(I)Ljava/lang/Object ;
[0046]在这个例子中,“invoke-virtual”表示在此处进行虚函数调用。“v2,vl”为寄存器列表,寄存器”v2”保存类型为Ljava/util/ArrayList ;的对象;寄存器”vl”保存类型为I 的数据。“Ljava/util/ArrayList ;->get (I) Ljava/lang/0bject ; ”表示在此指令执行时被调用的函数。
[0047]在上面的例子中,尽管“Ljava/util/ArrayList;->get (I) Ljava/lang/0b ject ; ”只声明了一个参数,但是按照Smali语言的参数传递规则,在实际传参时,还是需要传递两个参数。

【发明内容】

[0048]本发明的目的就是为了克服上述现有技术存在的缺陷而提供一种基于插桩技术的安卓应用软件自动化测试方法。
[0049]本发明的目的可以通过以下技术方案来实现:
[0050]一种基于插桩技术的安卓应用软件自动化测试方法,包括以下步骤:
[0051]步骤一、反编译被测试安卓应用软件,生成资源文件与smali源文件;
[0052]步骤二、编写探针代码,在smali源文件中插入探针代码,获得修改后的smali文件;
[0053]步骤三、对步骤二获得的smali文件进行重新编译,生成用于测试的应用软件,采用该应用软件完成被测试安卓应用软件的测试。
[0054]所述的步骤二中,插入探针代码的方法为:修改类继承关系,实现探针代码的插入,具体如下:[0055]al)被测试安卓应用软件经反编译后获得基类和目标类,基类是目标类的父类,在目标类中存在对父类的目标函数的调用;
[0056]a2)构造一探针类,该探针类是基类的子类,完全重载了父类的构造函数,探针类的构造函数均调用父类的具有相同参数类型的构造函数;
[0057]a3)探针类重载所述目标函数,重载后的目标函数中包括探针代码和对目标函数的调用;
[0058]a4)修改目标类的父类为探针类,即将探针代码插入目标类中。
[0059]所述的步骤二中,插入探针代码的方法为:替换对非静态函数的调用,实现探针代码的插入,具体如下:
[0060]bl)被测试安卓应用软件经反编译后获得一类A,该类A中存在对类B的一非静态函数的调用,该非静态函数称为目标函数;
[0061]b2)构造一探针函数,该探针函数为全局静态函数,包括探针代码与对目标函数的调用,且探针函数的第一个参数的类型为目标函数所属的类型,后续参数与目标函数完全相同;
[0062]探针函数调用目标函数时,调用的对象为第一个参数,传递给目标函数的参数为第一个参数的后续参数,同时保持参数的个数与顺序不变;
[0063]b3)将目标函数替换为探针函数,实现探针代码的插入。
[0064]将目标函数替换为探针函数时,还包括将非静态函数调用指令修改为静态函数调用指令的步骤。
[0065]所述的步骤二中,插入探针代码的方法为:替换静态函数,实现探针代码的插入,具体如下:
[0066]Cl)被测试安卓应用软件经反编译后获得一类A,该类A中存在对类B的一静态函数的调用,该静态函数称为目标函数;
[0067]c2)构造一探针函数,该探针函数为全局静态函数,包括探针代码与对目标函数的调用,且探针函数的所有参数与目标函数完全相同;
[0068]探针函数调用目标函数时,传递给目标函数的参数与传入的参数完全一致;
[0069]c3)将目标函数替换为探针函数,实现探针代码的插入。
[0070]所述的探针函数的名称与目标函数的名称相对应。
[0071]与现有技术相比,本发明在smali语言下,采用插桩技术编写探针代码并实现探针代码的插入,最后完成安卓应用软件的测试,方法简便,测试可靠,解决了现有技术中在robotium框架下进行测试的缺点。
【专利附图】

【附图说明】
[0072]图1为本发明的流程图;
[0073]图2为本发明的原理示意图。
【具体实施方式】
[0074]下面结合附图和具体实施例对本发明进行详细说明。本实施例以本发明技术方案为前提进行实施,给出了详细的实施方式和具体的操作过程,但本发明的保护范围不限于下述的实施例。
[0075]如图1所示,为了能够保证被测安卓应用原有的逻辑完整性以及插桩的可行性,本发明方法分为以下几步:
[0076]—、反编译被测试安卓应用
[0077]在对安卓应用进行反编译后会生成资源文件与smali源文件文件。
[0078]二、实现探针代码,插入探针代码
[0079]根据Smali语言的语法与面向对象编程的特点,通过以下三种方法实现探针代码的插入。
[0080]方法一:修改类继承关系,实现探针代码的插入。
[0081]此方法的原理如下:
[0082]假设被测试的应用反编译后得到类A和类C。类C是类A的子类,也就是说类C继承了类A所有的非私有方法。在类C中存在对父类的非私有方法f的调用。现需要在类C中对父类的非私有方法f的调用时插入探针代码。
[0083]首先,根据类的继承属性,在代码中加入类B。类B是类A的子类,它重载了类A的非私有方法f。在类B的方法f中,存在探针代码和对类A的非私有方法f的调用。这样,当类B的非私有方法f被调用时,探针代码与类A的非私有方法f都得到执行。而且,不考虑探针代码的逻辑时 ,类B的非私有方法f的逻辑与类A的非私有方法f的逻辑完全一致。
[0084]然后,修改类C的继承关系,使类C的继承自类B。这样,类C在调用父类的非私有方法f时,会首先调用类B的非私有方法f,再由类B调用类A的非私有方法f。由于类B的非私有方法f的逻辑与类A的非私有方法f的逻辑保持一致,所以这种修改实现了将类B的非私有函数f中探针代码插入到类C的代码中,而且没有影响到类C原有的逻辑。
[0085]使用此原理的进行探针代码插桩时,作为需要插入探针代码的类被称为目标类,例如类C ;目标类的原始父类被称为基类,例如类A ;提供插桩代码的类被称为探针类,例如类B。它是基类的派生类,也是插桩完毕后目标类的父类;在基类中,作为插桩目标的函数被称为目标函数,例如类A中的非私有函数f ;在探针类中,用于替代目标函数的函数被称为探针函数,它是通过对基娄中的目标函数重载而得。
[0086]根据此原理,可以根据插桩的目标编写探针代码。在编写探针代码时,需遵循如下规则:
[0087]1.探针类与目标类具有相同的父类。
[0088]2.探针类完全重载了父类的构造函数。探针类的构造函数均调用父类的具有相同参数类型的构造函数。
[0089]3.探针类重载目标函数。
[0090]4.探针类的目标函数由探针代码与对目标函数的调用组成。
[0091]由于Smali语言与Java语言是--对应的,所以可以使用Java根据此规则编写
探针类与探针函数,然后再使用反编译工具将探针类的代码转换为Smali语言的源代码。
[0092]根据此原理,将探针代码插入到目标类的修改过程如下:
[0093]①修改目标类的父类为探针类,即修改目标类的源文件中关于父类的伪指令super”的参数,使用探针类代替基类。
[0094]②在目标类的smali文件中查找对目标函数的调用指令。[0095]③修改目标类的smali文件中的对目标函数的调用指令。保持指令及寄存器列表不变,修改指令调用的函数,使用探针类中对应的函数替代基类的函数。
[0096]这个规则的具体替换过程可以参见下面的例子。在下面的例子中,基类是FragmentActivity,目标类是TabletMainActivity,探针类是DroidboxFragmentActivity。
[0097]探针加入之前的代码:
[0098]
【权利要求】
1.一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于,包括以下步骤: 步骤一、反编译被测试安卓应用软件,生成资源文件与Smali源文件; 步骤二、编写探针代码,在smali源文件中插入探针代码,获得修改后的smali文件;步骤三、对步骤二获得的smali文件进行重新编译,生成用于测试的应用软件,采用该应用软件完成被测试安卓应用软件的测试。
2.根据权利要求1所述的一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于,所述的步骤二中,插入探针代码的方法为:修改类继承关系,实现探针代码的插入,具体如下: al)被测试安卓应用软件经反编译后获得基类和目标类,基类是目标类的父类,在目标类中存在对父类的目标函数的调用; a2)构造一探针类,该探针类是基类的子类,完全重载了父类的构造函数,探针类的构造函数均调用父类的具有相同参数类型的构造函数; a3)探针类重载所述目标函数,重载后的目标函数中包括探针代码和对目标函数的调用; a4)修改目标类的父类为探针类,即将探针代码插入目标类中。
3.根据权利要求1所述的一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于,所述的步骤二中,插入探针代码的方法为:替换对非静态函数的调用,实现探针代码的插入,具体如下: bl)被测试安卓应用软件经反编译后获得一类A,该类A中存在对类B的一非静态函数的调用,该非静态函数称为目标函数; b2)构造一探针函数,该探针函数为全局静态函数,包括探针代码与对目标函数的调用,且探针函数的第一个参数的类型为目标函数所属的类型,后续参数与目标函数完全相同; 探针函数调用目标函数时,调用的对象为第一个参数,传递给目标函数的参数为第一个参数的后续参数,同时保持参数的个数与顺序不变; b3)将目标函数替换为探针函数,实现探针代码的插入。
4.根据权利要求3所述的一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于,将目标函数替换为探针函数时,还包括将非静态函数调用指令修改为静态函数调用指令的步骤。
5.根据权利要求1所述的一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于,所述的步骤二中,插入探针代码的方法为:替换静态函数,实现探针代码的插入,具体如下: Cl)被测试安卓应用软件经反编译后获得一类A,该类A中存在对类B的一静态函数的调用,该静态函数称为目标函数; c2)构造一探针函数,该探针函数为全局静态函数,包括探针代码与对目标函数的调用,且探针函数的所有参数与目标函数完全相同; 探针函数调用目标函数时,传递给目标函数的参数与传入的参数完全一致; c3)将目标函数替换为探针函数,实现探针代码的插入。
6.根据权利要求3或5所述的一种基于插桩技术的安卓应用软件自动化测试方法,其特征在于, 所述的探针函数的名称与目标函数的名称相对应。
【文档编号】G06F11/36GK103970659SQ201410210389
【公开日】2014年8月6日 申请日期:2014年5月16日 优先权日:2014年5月16日
【发明者】刘玉光 申请人:刘玉光
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1