美文网首页
【友盟+】首创SDK自动化测试框架,解决SDK测试痛点

【友盟+】首创SDK自动化测试框架,解决SDK测试痛点

作者: 友盟全域数据 | 来源:发表于2017-12-11 12:26 被阅读0次

    作者:【友盟+】高级无线开发工程师 吴玉强、王飞

    为了确保SDK线上运行的稳定性,我们需要在开发后进行SDK测试,而为了提高测试效率,而且在拓展新项目的同时能兼顾已有项目的稳定性,在有限的资源内解放测试人员到更紧急的项目中来,就需要一个自动化工具来完成工作,【友盟+】首创自动化工具,能够自动传不同参数、抓取输出数据,并自动验证数据准确性,输出结果,保障项目顺利稳定发布。

    相对App的测试方案,市面上已经有非常多且成熟的UI级别的自动化测试框架,却鲜有针对SDK提供的自动化测试方案,原因是SDK属于为App提供服务的“插件”。一个App可接入一到多个SDK在内,而在项目中模块化是非常普遍的架构,所以SDK是针对细分功能提供服务的组件,有的提供数据服务、地图服务或节省开发成本的组件等等,这只能SDK开发者根据功能自行完成测试。

    本篇说明的SDK测试方案是针对数据服务的SDK功能覆盖,皆包含SDK的API、网络数据及缓存相关的逻辑测试,即非UI的纯数据逻辑的覆盖。

    本篇是自动化测试基础上的延伸,相对安卓系统可以便利的通过adb指令控制如App安装、卸载、退出应用等“系统”级操作,iOS在控制App层面上只能通过一些间接的手段完成上面几点需求,为了易于维护,在控制器中以有限状态机模式进行了构造,以便于后续增加更多的操作状态和测试用例。

    一、测试框架概览

    1、测试框架

    整个测试流程就如下面描述的有向图,以Pytest驱动客户端执行任务,然后将客户端输出的请求数据进行截取处理,而后验证是否通过测试用例。

    2、Android端测试框架

    Android可以使用adb命令与app进行数据上的通信,如发送广播,启动Activity等。同时也可以使用shell命令对配置文件进行修改,再进行gradle编译,实现对app级别参数的修改,从而完成不同参数对app程序影响的验证。

    3、iOS端测试框架

    iOS由于系统特性,无法如安卓系统灵活运用系统命令来操作App或SDK,所以以一个Socket连接Server端进行通信。

    另外在iOS系统上又可利用Runtime的特性,将传输的字符串转化为API调用,这样做的好处是将Socket模块和Runtime解析模块编入应用中就无需再次打包,只需Python端编好代码和测试case,所有的功能调用都由两端约定的协议解析执行即可。

    二、Android

    1、SDK接口的验证

    对于集成SDK的app,如果需要在App运行时,触发一个行为,可以通过广播来实现。可以根据action name完成对行为类型的分类,根据caseid完成对行为的区分。如下图所示:

    根据上图示例如下:

    os.system("adb shell am

    broadcast -a com.umeng.auto.track --es param \""+ str(es) +"\"--ei caseId "+bytes(ei))

    其中com.umeng.auto.track为广播的action name用以区分类别

    ei为一个int数,相当于图中的caseid

    es为参数内容,参数的协议可以自由定义,建议使用json类型,方便对不同类型的数据进行处理

    这样,我们只需要在广播中以ei写一个switch语句,执行不同的行为,如果测试不同参数的效果,可以使用es传递内容。

    2、Activity级别初始化的验证

    如果使用广播,是没办法绑定生命周期,即如果SDK需要在Activity的onCreate()中进行一些类初始化操作,是没法进行控制的。所以对于这种情况就需要使用adb命令中的启动Activity命令,基本流程与广播类似,但是caseid的处理在onCreate()中:

    根据上图示例如下:

    os.system("adb shell am start -n " +self.pkgname + "/." + activity + " --es param \"" + str(es)+ "\"--ei caseId " +bytes(ei))

    其中pkgname为包名,activity为activity的名字es为需要传入的内容,ei为一个int数,即caseId。

    与广播方式类似,只是将switch放到了onCreate中,根据ei和es进行相应的操作。

    3、Application级别的验证

    以上说的两种方式几乎可以涵盖SDK测试的部分case,但是对于部分SDK,初始化需要在程序一启动的Application中执行,这时上面的两种方式显然满足不了需求。

    这时有两套方案可以应对。如下图所示:

    二次编译

    如上图所示,左边的部分,我们可以通过修改Java文件完成对Appliction中内容的修改,如在Application中会有一些静态常量,使用python修改java文件中的常量,并重新运行:

    defchangeConstant(self, source,des):

    path =os.path.join(os.path.dirname(sys.path[0]),'autotestAndroid')

    gradle_path =os.path.join(path,'app','src','main','java','deep','autotest','utils','Constant.java')

    print'-----gradle_path----',gradle_path

    ifos.path.exists(gradle_path):

    build_file =open(gradle_path,'r+')

    lines = build_file.readlines()

    foriinrange(len(lines)):

    line = lines[i]

    if' '+sourceinline:

    arr =line.split('=')

    line = arr[0]+'='+des+";\n"

    lines[i] = line

    build_file =open(gradle_path,'w+')

    build_file.writelines(lines)

    p =buildprocess.CompileProcess(path)

    p.start()

    else:

    print'nonono='+ gradle_path

    使用这种方式的好处是:

    [if !supportLists]•[endif]可以直接修改Application中的常量,如AppKey等,不用管是否执行了Application的onCreate()

    [if !supportLists]•[endif]不用考虑外设情况

    [if !supportLists]•[endif]同样适配对AndroidManifest.xml的测试

    缺点是:

    [if !supportLists]•[endif]需要绑定工程路径

    [if !supportLists]•[endif]文件内容类型较多,容易出错,代码不具备通用性,有一定的二次开发难度

    [if !supportLists]•[endif]需使用gradle重新编译,如工程较大,耗时较长

    配置文件

    除了上述方法,也可以在Application中读取一个SD卡配置文件,根据配置文件的协议进行对应的操作。每次只需更改配置文件的内容,并通过adb push放入SD卡指定路径中,然后重启App即可。

    这样做的好处是:

    [if !supportLists]•[endif]配置文件的协议可以随意定义,更灵活

    [if !supportLists]•[endif]配置文件可以使用json格式,修改更简单

    [if !supportLists]•[endif]只需推到SD卡,耗时更少

    [if !supportLists]•[endif]不需要绑定工程路径

    缺点是:

    [if !supportLists]•[endif]只能在Application的onCreate之后进行,局限性较大。

    [if !supportLists]•[endif]依赖外设SD卡

    [if !supportLists]•[endif]AndroidManifest的测试无法使用。

    三、iOS端SDK自动化测试流程

    1、引入“守护”App

    如「iOS端测试框架」所见,此时进行通信只有一个应用,这个应用就是我们用来测试SDK的Demo,通过这个宿主我们可以触发SDK提供的任何API,通过iOS runtime我们可以触发SDK的类方法、实例方法甚至是私有API,但这写都只局限于一个应用“沙盒”内,如上面说到的安装、卸载及App退出和切到后台就无能为力了,所以我们引入了另一个Demo(Watch Demo),通过两个Demo的协同操作满足“沙盒”之外的需求。


    两个App互相唤醒和通信

    如上面提到的,所有功能调用都基于约定的协议来执行的,协议的设计也是不断新增的测试需求改造的。

    2、业务协议

    最初Server端与客户端以测试用例的case id来区分需要触发的事件,后来case id所代表的含义太多,而且客户端也是以运行时不断调用Server端发送指令的形式表现执行的具体功能,所以转为一条执行序列更加灵活及方便扩展。

    一个测试用例可分为多条执行序列,执行序列内的协议包含了需要进行的方法调用或事件的处理。

    以Dplus为例,如下数据包含了部分操作的执行序列:

    "operations":{

    "$umeng_cloudayc_op9": {

    "arguments": {

    "param": [

    "$umeng_cloudayc_op*"

    ]

    },

    "type": "class",

    "class":"DplusMobClick",

    "method": "track:"

    },

    "$umeng_cloudayc_op5": {

    "arguments": {

    "param": []

    },

    "next":"$umeng_cloudayc_op9",

    "type": "class",

    "class":"DplusMobClick",

    "method":"clearSuperProperties"

    }

    },

    "type":"invoke",

    "description":"401",

    "first": "$umeng_cloudayc_op5"

    由于是针对SDK API测试的协议,所以协议内的格式以调用的类名、方法名及参数为主,再加上部分细节参数加以说明,如type是class则调用类方法,是instance是示例方法。

    需要注意的是,这个队列的结构是个字典,以标识前缀$umeng_cloudayc_op作为一个子事件的key,value则是其执行参数。而且可以看到在参数param的value里也有和子事件的key类似的值,这里的设计也是为了满足部分嵌套调用的需求。举例来说,如此时需要通过一个接口验证之前缓存的数据是否发送正常,就要分三步,第一存储数据,第二将数据读出,第三将第二步的结果作为参数传入最后调用的接口即可,这样既能满足各种嵌套逻辑,又能实现远程构造客户端系统的实体对象作为参数进行接口调用。

    回到上面的字典的结构,实际上在之前的协议格式使用的是数组作为执行序列的封装格式,不过在实际应用中无法满足灵活的要求,就如上面所说的组合的调用逻辑,有部分子事件是被动调用的,通过在其他事件内的参数检测来触发调用,如果是数组则无法控制这个执行序列的依赖关系。采用字典后,增加启动字段,在后续关联的子事件内,都会说明下一个执行的子事件,如果某个子事件是作为另外子事件的参数,则不会有next字段,因为它是被动触发的,不在执行队列之内。

    在这个业务协议开发过程中,不断的根据测试需求进行改造、添加,从一开始的单一应用调用接口,到后面的多应用切换、前后台切换以及应用断开和重连,需要多套控制流程,在具体实现时,分散到了各个业务逻辑中,每增加一个控制都要兼容考虑是否会影响到其他模块,而且作为一个自动化测试“框架”,提前梳理好核心部分的流程会让之后更易于开发和维护,所以就引入了有限状态机的概念进行构造。

    3、有限状态机

    有限状态机(Finite-state machine)可用于模拟很多事物逻辑,顾名思义,它是一个有限的状态的处理逻辑,有下面几个特征:

    状态数是有限的

    在当前时刻只有一种状态存在

    一个状态在满足某个条件后会切换到另一状态

    而有限状态机整体可以归纳为四个要素:现态、条件、动作以及次态。

    现态指当前时刻所表现的状态

    条件又称为事件,即当前状态在满足这个条件后会触发一个动作,从而进行状态装换

    动作即在现态满足条件后需触发的一系列操作,动作完成后即状态进行迁移。动作也可以忽略,在某些情况下,现态满足条件后,也无需执行任何动作就切换到新的状态。

    次态是相对现态而言,表示了条件满足后迁移的状态,次态也可以与现态相同。

    根据业务逻辑的特性及复杂程度,合适的使用有限状态机,可以使得逻辑表达清晰、封装及维护都很直观和方便。当一个业务包含的状态越多,就越适合使用优先状态机进行封装处理。

    有限状态机应用非常广泛,如电子电路、编译器及网络协议TCP协议状态机等

    需要注意的是要区分“动作”和“状态”,如果将“动作”也视为“状态”会导致编写状态机时产生问题。

    4、有限状态机应用自动化测试

    将业务逻辑应用到有限状态机,前提是需要熟悉对应的业务,并将其中的状态、动作和条件等抽离出来,然后再做进一步的划分和关联,构造出一个完整的有向图。

    在自动化测试中,有如下几个关键词:

    启动测试、监听、主App连接、守护App连接、接口调用、进入后台、进入前台、应用退出、崩溃、断开连接、重连等。

    在日常开发中,如果遇到上面的”事件”,可能就顺其自然的开始写判断、写调用,可能不自觉的就写出了一个“有限状态机”,不过不会那么严格的区分什么是动作什么是状态,只要满足最后的结果就能达成目的。

    但现在我们有意识的利用有限状态机进行划分,分离出状态和动作以及状态迁移的条件。看上面的关键字,好像都是一个个“动作”,仔细看“监听(中)”又可能是一个状态,但实际上我们还得需要结合业务的理解再抽象出一些状态,如“进入后台”,则是跳转到了守护App,当前是控制守护App的状态;若是“进入前台”则守护App跳转到了“主App”,是控制主App的状态。

    如下图就用刚才抽象出的关键词构造了一个简单的有限状态机:

    按图说明:

    如架构图描述的,需要主App和守护App同时连接才可执行测试

    在连接完成后,状态直接迁移到等待测试指令的状态,没有任何动作

    有些组合状态可以合成一个状态,如运行守护App状态时可能主App断开连接,也可能保持连接,所以区分为两态分别管理

    当自动化测试框架启动后,除了监听两个App同时连接,其他状态都是在已有App连接完成的前提下进行的,所以大部分时间是在执行测试case调用及App切换的。

    相关文章

      网友评论

          本文标题:【友盟+】首创SDK自动化测试框架,解决SDK测试痛点

          本文链接:https://www.haomeiwen.com/subject/valiixtx.html