AICon议程上新60%,阿里国际、360智脑、科大讯飞、蔚来汽车分享大模型探索与实践 了解详情
写点什么

SDK 如何进行自动化测试?

  • 2017-12-21
  • 本文字数:4855 字

    阅读完需:约 16 分钟

相对 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 数,相当于图中的 caseides 为参数内容,参数的协议可以自由定义,建议使用 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 文件中的常量,并重新运行:

复制代码
def changeConstant(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
       if os.path.exists(gradle_path):
           build_file = open(gradle_path, 'r+')
           lines = build_file.readlines()
           for i in range(len(lines)):
               line = lines[i]
               if ' '+source in line:
                   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

使用这种方式的好处是:

  • 可以直接修改 Application 中的常量,如 AppKey 等,不用管是否执行了 Application 的 onCreate()
  • 不用考虑外设情况
  • 同样适配对 AndroidManifest.xml 的测试

缺点是:

  • 需要绑定工程路径
  • 文件内容类型较多,容易出错,代码不具备通用性,有一定的二次开发难度
  • 需使用 gradle 重新编译,如工程较大,耗时较长

配置文件

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

这样做的好处是:

  • 配置文件的协议可以随意定义,更灵活
  • 配置文件可以使用 json 格式,修改更简单
  • 只需推到 SD 卡,耗时更少
  • 不需要绑定工程路径

缺点是:

  • 只能在 Application 的 onCreate 之后进行,局限性较大
  • 依赖外设 SD 卡
  • 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)可用于模拟很多事物逻辑,顾名思义,它是一个有限的状态的处理逻辑,有下面几个特征:

  1. 状态数是有限的;
  2. 在当前时刻只有一种状态存在;
  3. 一个状态在满足某个条件后会切换到另一状态;
  4. 而有限状态机整体可以归纳为四个要素:现态、条件、动作以及次态。

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

条件又称为事件,即当前状态在满足这个条件后会触发一个动作,从而进行状态装换动作即在现态满足条件后需触发的一系列操作,动作完成后即状态进行迁移。动作也可以忽略,在某些情况下,现态满足条件后,也无需执行任何动作就切换到新的状态。次态是相对现态而言,表示了条件满足后迁移的状态,次态也可以与现态相同。根据业务逻辑的特性及复杂程度,合适的使用有限状态机,可以使得逻辑表达清晰、封装及维护都很直观和方便。当一个业务包含的状态越多,就越适合使用优先状态机进行封装处理。有限状态机应用非常广泛,如电子电路、编译器及网络协议 TCP 协议状态机等

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

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

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

在自动化测试中,有如下几个关键词:启动测试、监听、主 App 连接、守护 App 连接、接口调用、进入后台、进入前台、应用退出、崩溃、断开连接、重连等。

在日常开发中,如果遇到上面的”事件”,可能就顺其自然的开始写判断、写调用,可能不自觉的就写出了一个“有限状态机”,不过不会那么严格的区分什么是动作什么是状态,只要满足最后的结果就能达成目的。但现在我们有意识的利用有限状态机进行划分,分离出状态和动作以及状态迁移的条件。看上面的关键字,好像都是一个个“动作”,仔细看“监听 (中)”又可能是一个状态,但实际上我们还得需要结合业务的理解再抽象出一些状态,如“进入后台”,则是跳转到了守护 App,当前是控制守护 App 的状态;若是“进入前台”则守护 App 跳转到了“主 App”,是控制主 App 的状态。

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

按图说明:

  1. 如架构图描述的,需要主 App 和守护 App 同时连接才可执行测试;
  2. 在连接完成后,状态直接迁移到等待测试指令的状态,没有任何动作;
  3. 有些组合状态可以合成一个状态,如运行守护 App 状态时可能主 App 断开连接,也可能保持连接,所以区分为两态分别管理;
  4. 当自动化测试框架启动后,除了监听两个 App 同时连接,其他状态都是在已有 App 连接完成的前提下进行的,所以大部分时间是在执行测试 case 调用及 App 切换的。

感谢徐川对本文的审校。

2017-12-21 17:0427924

评论

发布
暂无评论
发现更多内容

anyRTC Web SDK 实现音视频呼叫功能

anyRTC开发者

音视频 WebRTC RTC sdk

GitHub火到糊!这份阿里内部10W字Java面试总结,让你薪资翻倍

Java架构追梦

Java 架构 面试 跳槽

【融云技术】超大规模并发下自定义属性的设置与分发

融云 RongCloud

华为云IoT设备接入服务全体验

华为云开发者联盟

物联网 IoT 华为云 智能IoT边缘服务 华为云IoT云服务

6000年,看懂了「硬核山东」!

云计算

踩准时钟节拍、玩转时间转换,鸿蒙轻内核时间管理有妙招

华为云开发者联盟

鸿蒙 时间管理 计数器 时间转换 计时

亮相Google I/O,字节跳动是这样应用Flutter的

字节跳动技术团队

Overbit Flash|5 月加密货币市场风暴抹去了 90% 以上的 NFT 交易量

Overbit学院

比特币 加密货币 NFT Overbit 保证金交易

☕【JVM技术之旅】全流程化分析Java对象的创建过程

洛神灬殇

JVM 6月日更 对象布局 内存结构

有点难的知识点:Webpack Chunk 分包规则详解

范文杰

webpack 6月日更

🏆【声网Agora】「WebRTC-如何搭建语音认证服务」

洛神灬殇

WebRTC RTC征文大赛 Agora 6月日更

C++多线程强制终止

华为云开发者联盟

c++ 安全 线程 多线程 可信

什么是交叉编译

IT蜗壳-Tango

IT蜗壳教学 6月日更

难忘阿里,4面技术5面HR附加笔试面,走的真艰难真心酸

Java 编程 程序员 面试 架构师

华云大咖说 | 安超OS全面升级 最新亮点解密

华云数据

获5项大奖,发布《云计算开放应用架构标准》,阿里云持续领航云原生

阿里巴巴中间件

前后端分离浅析以及分离教程

北游学Java

前后

裕民银行 x mPaaS | 移动应用“适老化”改造,可不止是字体变大

蚂蚁集团移动开发平台 mPaaS

移动开发 mPaaS APP开发

和12岁小同志搞创客开发:如何驱动各类型传感器?

不脱发的程序猿

DIY 传感器 如何驱动各类型传感器? 创客

新手小白必须知道的Linux基础:常用命令(1)

学神来啦

Linux linux命令 linux运维 linux 文件权限控制 Linux教程

详解浏览器跨域访问的几种办法

华为云开发者联盟

安全 浏览器 跨域 WEB安全 跨域访问

【Flutter 专题】113 图解自定义 ACEPieWidget 饼状图 (二)

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 6月日更

ETL工程师必看!超实用的任务优化与断点执行方案

敏捷调度TASKCTL

大数据 ETL算法 ETL ETL任务 ETL系统

分库分表 vs NewSQL 数据库

xcbeyond

分库分表 6月日更

音视频学习--弱网对抗技术相关实践

Fenngton

音视频 网络 视频编解码 弱网下的极限实时视频通信 实时视频

【LeetCode】连续数组Java题解

Albert

算法 LeetCode 6月日更

为鸿蒙OS说两句公道话(我对鸿蒙OS的一些看法)

Phoenix

Qcon全球软件开发大会 融云分享SDK交付质量保障经验

融云 RongCloud

Java日志的心路历程

程序猿阿星

Java log4j logback log4j2框架 Java日志

从一面就被拒到收割字节offer,我花了一年时间,功夫不负有心人

Java架构师迁哥

C 语言数据结构的封装方法

实力程序员

SDK如何进行自动化测试?_语言 & 开发_吴玉强_InfoQ精选文章