爱奇艺iOS稳定性测试实践

Posted 爱奇艺技术产品团队

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爱奇艺iOS稳定性测试实践相关的知识,希望对你有一定的参考价值。

稳定性测试是长时间持续运行APP,以验证应用是否稳定的测试。它可以有效发现APP长时间运行下的偶发闪退、内存泄露、性能变差等问题。ios端通常由苹果系统的API快速执行点击事件,开展稳定性测试,类似的优秀工具如FastMonkey等虽然有诸多好处,但是作为长期运行的测试服务系统,还需要调整功能以适应企业级测试场景,无法解决通过外部请求定制事件执行序列、无法动态设置启动参数、截图存在本地将导致磁盘占用过大等问题。

爱奇艺测试团队在iOS稳定性测试方面展开了不懈的探索,也积累了一些相关经验,希望借本文跟大家分享在【iOS稳定性测试】实践和优化过程中的心得和体会,也借此机会抛砖引玉,征求同行的更多探讨。

01

方案实践

1.1基础框架
爱奇艺iOS稳定性测试基于现有的云真机体系,总体分为三大块。向下是设备管理,向上是产出物汇总,核心是测试策略。基础框架如下图1,真机设备通过驱动层接入远程控制体系,统一由后端调度管理,核心策略通过设备驱动与真机设备交互,模拟用户行为开展测试,测试过程中产生的数据统一汇总到后端,由后端生成测试报告并反馈给用户。


图1. 系统框架

系统结构如上,下面重点讨论策略选择的问题。

常用的稳定性测试方案,有Monkey测试、录制回放或者按元素遍历的方式等。其中Monkey测试实现成本较低,但有的页面元素较少,盲目的操作经常点不到元素,导致测试效率较低;对于长期执行录制回放的方案,其执行路径固定且与业务功能耦合,可能需要长期维护业务逻辑,不利于各业务线快速拓展稳定性测试场景;而按元素遍历操作的方案,可以较好的处理上述方案的问题,但是实现成本比Monkey策略高,需要测试团队持续投入研发力量。

我们尝试了随机滑动点击策略、按元素点击的遍历策略,下面分析下两种方案的实现细节和难点。

1.2生成测试事件

我们抽象出一个模块叫事件生成器,主要作用是持续产生用户事件流作用于APP,以达到验证APP稳定性的目的。本文重点介绍随机产生和根据页面元素产生两种模式。

随机产生事件

随机事件方案的典型代表是Monkey,它向系统发送随机的用户事件流(如点击、输入、滑动等),实现对正在开发的应用程序进行稳定性测试。该方案通过XCTest提供的接口就可以快速模拟相关操作,实现成本相对较低。早期为了快速打通测试流程,验证方案有效性,我们实现了Monkey测试的方案。如图2所示:先获取本次任务期望各事件发生的占比配置(涉及重启APP、按home键、切换横竖屏、点击事件、滑动事件、后退等事件),再按概率指定本次执行哪种事件。组装好需要执行的事件,最后请求具体的驱动服务以执行事件。

图2  随机事件生成器

根据页面元素产生事件

随机策略虽然点击频率高,但是无效事件占比高达90%。分析测试报告发现当页面可点击元素较少时,随机生成器产生的事件就会触发大量无效操作。如果可以根据页面的可操作元素进行遍历操作,就可以大大减少无效事件的产生。因此尝试使用按元素点击的策略,执行深度/广度优先遍历策略,提升测试效率。

那iOS端如何获取元素、记录执行路径以及按元素来遍历的方式执行测试策略呢?

  • 识别页面上的元素


  • 按元素点击首先要解决元素识别的问题。

    方法1,被测APP集成SDK,接入成本高,且正式包一般不允许带入;

    方法2,从DOM树解析元素,存在DOM树元素累积的情况,当页面分页时,无法区分仅当前页的元素,影响元素解析准确性。

    这两种方法都存在一定的问题,因此我们把眼光转向了方法3,AI图像识别元素。AI图像识别作为一项相对成熟的技术可以有效避免上述问题,并提供相对准确的元素数据。因此在元素生成方面,我们借助爱奇艺内部提供的AI服务,在事件操作前将画面截屏传递给AI服务,快速识别绝大多数元素区域,如下图3所示。

    图3 AI服务识别页面的元素


  • 对多个页面去重,定位当前所处页面


  • 解决了元素识别的问题后,下一步就是解决元素遍历的逻辑。为提高遍历效率,遍历逻辑需要尽可能的避免多次进到重复的页面遍历。为了定位到当前所处页面以记录执行路径,顺带避免相同页面重复请求AI服务,需要对当前页面是否曾经进入过进行判断,我们考虑的方法有2个:

    方法1,从DOM树提取关键信息来生成指纹,以指纹定位当前所处的页面。但经过实践发现获取DOM树的接口耗时不稳定,经常耗时>4s,不利于快速定位页面。

    方法2,利用事件操作前后的屏幕截图生成像素指纹,来定位当前所处的页面。实践发现通过此方法定位页面,速度可达到毫秒级别。

    大致流程如图4,先获取屏幕截图,再把截图处理灰度化、缩放为8*9的缩略图,最后再生成包含图像信息的指纹。通过计算指纹之间相似度是否超过阈值来判定图片是否为同一张,从而判断处在哪一页。优点是后续可直接通过指纹计算页面之间的相似度,速度较快,也通过提高阈值避免局部细微变化干扰判断结果。

    图4 以屏幕截图生成指纹判断相似度


  • 返回上一个页面


  • 广度优先算法每个步骤点击成功都需要返回上页,继续点击该页其他元素;深度策略点到没元素点击的页面也需要尝试返回以继续点击,所以实现通用返回策略是有必要的。不同于android有物理按键强制返回,iOS端需要自己来实现一套返回方法。结合被测APP特性,我们封装的返回逻辑是,大部分页面可左滑返回上一页,禁用左滑的页面则靠以下方式来处理。

    1. 比如H5页面的关闭导航按钮等,可识别DOM树中属性包含back/close字样的元素为返回、关闭按钮,尝试点击以返回上一页;

    2. 部分页面导航按钮以“返回”文字呈现,方法1就找不到这种退出按钮。我们把屏幕截图上传给OCR文字识别服务,识别屏幕中的“返回”文字。点击识别到的返回文字以尝试返回上一页;

    3. 部分广告浮层的关闭按钮是“X”图样的关闭图片,上述两方法都不能处理。我们则批量搜集此类关闭图样训练了可以识别关闭按钮位置的AI工具,通过点击识别的元素位置以返回上一页。


    所以我们如示意图5,按元素深度优先遍历策略单步事件执行。

    图5 元素事件生成器

    处理运行时的突发干扰

    实践发现,自动化测试运行时可能存在偶发的弹窗阻挡点击目标元素、可能误操作使APP退到了后台,也可能在某页卡住无法退出。如何处理各种阻碍测试的异常,确保APP测试过程中可以触达更多的页面,提升测试覆盖程度呢 ?

    部分应用进不去首页的解决

    有的APP必需先执行登录等操作才能进入首页开始测试任务。各个业务线情况多种多样,所以框架支持定制化脚本的运行。允许让用户定制差异化的前置场景,在运行稳定性测试前先执行定制脚本,再开始稳定性测试。


    偶然的弹窗面板处理


    APP运行过程中出现的弹窗多种多样,大致可分为如下表格6中几类:

    表格6 弹窗情况分类

    系统弹窗检测和处理相对简单,只需要提前设置要识别的文本,WDA接口通过文本属性判断元素存在则直接点击掉。但是当业务线越来越多,需要设置的文本数量也急剧增长,每步事件操作前都需要循环判断是否有满足设定文本的弹窗,时间损耗太大。

    研究发现iOS的“正则表达式”-NSPredicate方式,支持一次请求判断多个元素是否存在,同时正则表达式的方式可以根据需求快速扩展,有效的避免文本的穷尽枚举。基于这样的新的思路,每步检测弹窗只需要请求WDA一次,即可判断N种文本,减少了N-1次网络请求耗时,提升执行效率。

    例如图7:当出现以下弹框时“label=\'取消\'or label=\'同意并继续\' or label=\'我知道了\'” ,一次请求即可判断多种弹窗文本是否存在,存在则逐一处理掉。

    图7 各种弹窗情况

          

    保持被测应用处在前台


    APP在操作过程中,可能因为某些操作跳出当前APP,因此保证当前被测APP一直在前台运行是十分有必要的。常见的方案有两种

    方法一,直接分析当前所处页面DOM树,获取XPath返回的XCUIElementTypeApplication属性,此属性值与被测APP名称一致则认为被测APP保持在最前台。但是当被测应用页面复杂时,XPath查询的速度会变慢,严重影响任务执行的单步耗时。

    方法二,利用苹果官方提供的接口activeApplication可直接输出当时前台应用的Bundle ID,返回的Bundle ID与被测应用一致就可以快速确认当前APP是否在前台。这样不再查询页面整体的XPath信息,避免返回过多的无用信息,也更稳定、快速。

    不过方法二也不能处理所有的情况,比如当手机打开了辅助功能(小白点)的面板、或者存在左上角的跳转返回其他应用按钮时,方法2会误判顶层APP为非被测APP。
     
    判断下发的事件是否有效执行

    稳定性任务运行过程中,如果遇到静态页面,在点击退出之前,当前页面触发的操作对于APP而言都是无价值的,我们称之为无效点击,为了尽量减少无效点击的数量,我们希望在操作事件之后进行判断,最直接的想法就是判断操作之后页面是否发生了变化。因此需要在事件操作前后进行截图,将截图直接生成均值hash的指纹作为图像的标记,连续2步骤之间的指纹汉明距离小于阈值则判断为同一页面 (图8)。连续2步骤相同则判定这个事件无效。

     图8  判断屏幕截图的相似度

    解决了测试事件的生成、处理好突发的情况,就可以按下述图9 服务框架循环执行测试服务。

    图9 服务框架

    02

    落地应用

    为了验证不同策略下的效果,我们进行了对比实验,每种策略单独运行20次,每次连续执行8小时,选取了事件总数、无效占比、单步耗时和页面覆盖数4个指标进行评价。对比数据见表10。

    表10 各策略数据对比表格

    在页面覆盖数方面,由于iOS端无法获取类似Android的Activity个数来统计,我们使用近似的数据来代替,利用测试过程中的事件截图,对截图去重来近似衡量页面覆盖数。

    页面覆盖数计算规则:每个图片计算指纹,图片之间通过指纹计算相似度,相似度过高则只计一页;累计所有的截图数量认为是此次任务的页面覆盖数。

    下图11中,X轴是测试执行时长,Y轴是画面覆盖数。可以看到8小时执行后新的按元素遍历策略覆盖率比随机点击策略提升了将近30%。

    图11 各策略覆盖的画面数随时间增长趋势图

    从几组数据来看,随机点击的平均单步耗时短、点击频率高,但是有效时间占比偏低。元素遍历策略在有效事件占比和页面覆盖数方面提升明显,但由于需要大量切图等操作,单步耗时较高。两种方式各有利弊,可以根据实际的测试场景进行选择,如果希望验证APP的抗压性可以选择随机策略,如果希望覆盖到更多的页面则可以选择元素遍历策略。

    2.1独立APP运行

    当前两种测试均在爱奇艺内使用,稳定性测试任务每月运行800+次,发现崩溃200+,在整个 DevOps 流程中扮演重要的基础服务角色。

    2.2模块指定页面执行

    除了在独立APP中运行,也有团队需要在指定的模块页面内开展稳定性测试,我们尝试在被测页面DOM树加入隐藏标识,周期性判断标识是否跳出了限定范围。该方案基本满足业务场景,可持续在限制页面范围内执行测试。但对程序也有一定侵入性,需要开发在页面增加定制化的属性,供测试工具判断是否跳出限定范围。

    03

    后续优化

    当前的稳定性测试策略都是蛮力点击和遍历,后续会拓展更多的更有针对性的遍历策略,比如追求用户实际操作情况的一致,尝试根据线上用户流量提取用户行为,生成更加切合用户实际的操作行为;追求bug发现效率,对历史上更容易出现崩溃的页面增加遍历权重等等。

    爱奇艺xWSDM发起
    用户留存预测挑战赛
    基于超400万现实场景
    累计的海量数据

    报名火热进行中!

    爱奇艺移动端APP健壮性测试的设计与实践

    在这里插入图片描述

    01前言

    一款APP的发布以及新功能的迭代需要经过严格的质量保证,而崩溃性问题是影响APP稳定的头号问题。其中,因前端不兼容后端服务数据格式变更而引起的崩溃问题占有一定的比例。这类崩溃问题一般排查难度较大,且利用常规测试方法通常很难有效降低这种类型缺陷的比例。

    是否有更好的方式来提前预防数据变更导致的崩溃问题? 本文将重点介绍爱奇艺技术产品团队打造的APP健壮性测试实践内容。

    02背景

    爱奇艺APP拥有丰富的视频资源,需要频繁进行节目上线或者下线、各种活动配置等操作调整。这些内容迭代主要是通过后台管理系统进行,然后下发到APP端并在UI层展示。在版本功能迭代过程中尽管有大量的、针对性的质量保证方法,但是服务端业务逻辑盘根错节,一些极少用到的功能配置可能在历经多次代码迭代后在最新版本APP中出现兼容问题,一些第三方依赖接口可能会因为格式的变化而引发前端UI不兼容甚至崩溃,这对于APP的健壮性、稳定性提出了很大的挑战。
    爱奇艺技术团队对线上历史问题进行总结、对行业内前沿技术进行探索,最终经过多次探讨后设计了一种APP健壮性测试方案。团队研发的基础网络库SDK对APP收到的服务端接口返回进行拦截,从网络层进行数据替换。团队根据历史问题的总结、日常经验的积累提炼出一系列数据组合,当APP进入需要测试的页面时,就会去拉取并进行“脏数据”填充,以便尽早发现因数据变更引发的崩溃问题。
    在这里插入图片描述

    测试效果图:从图中可以看到页面中的文字被脏数据修改

    03技术实现

    在这里插入图片描述

    从上图可以看到:

    1)策略配置是一个独立的Web化模块,APP内“脏数据”注入规则都由策略配置控制。

    2)APP内的基础网络库SDK模块是一个独立的功能模块,不会对其他功能模块有影响;并具有单独的开关控制,只有开关开启时才对后端返回的数据进行拦截替换。

    下面将对实现情况进行具体说明。

    一、WEB策略配置–可视化界面

    策略配置的前提是确认页面的哪些接口请求需要进行校验,通常一个页面有非常多的后端请求,每个请求都会带有很多不同类型的参数,对应的返回数据带了大量的KEY和VALUE,数据配置对测试结果尤其重要。丰富的高危“脏数据”才能极大的提升网络数据测试的效果,如果纯手工输入“脏数据“进行测试,人力成本较高,最终我们通过WEB可视化界面进行数据策略配置,大幅度减少用户对“脏数据”的设计成本,因此策略配置界面的原则是数据通配、操作简单、策略可复用。

    –策略示例图-1
    在这里插入图片描述

    –策略示例图-2
    在这里插入图片描述

    从策略示例图1、2可以看到,配置分为二部分:

    1)URL配置:

    被测页面的请求URL,支持域名模糊匹配、多域名同策略、域名参数匹配等。

    2)数据配置:

    支持单节点、多节点、节点移除/跳过;
    支持同类型、非同类型、emoji表情、#color、null 、空值、object等。
    可视化页面为用户提供多种默认策略,这些默认策略均是测试中提炼出的经验积累,用户仅需配置待测URL即可使用,极大地降低操作成本。

    二、策略通信原理

    鉴于测试的目标覆盖度以及测试任务执行效率两个维度考虑,我们具有两种遍历JSON的策略:

    1)刷新单个节点进行顺序访问

    此策略可以覆盖所有节点检查,根据返回结构,依次替换节点数据。具有节点全覆盖的特点。接口返回数据体量大时耗时会较长,所以此方式适用于UI自动化测试。

    2)刷新遍历所有节点的全节点访问

    此策略每次访问到匹配的URL时从列表内随机获取一个脏数据,对原数据进行替换。具有数据随机性强,遍历灵活度高的特点。接口返回数据体量无论大小,各个节点均有机会被替换,所以此方式适用于稳定性测试。

    遍历策略开发难点:

    任务过程中如有发生崩溃,重启APP后遍历执行仍然会在相同的崩溃节点反复测试,这导致测试效率低下后续测试步骤无法继续进行。为了解决这个问题,测试中SDK维护一个“脏数据”遍历的访问栈使用非递归遍历,会保存遍历栈到本地,不论是重启还是发生崩溃都可以直接从这个栈里恢复访问进度。

    SDK数据拦截实现:
    在这里插入图片描述

    通过基于ASM的hook框架编译时指定网络库对应的方法进行hook修改网络库的字节码实现拦截,将JSON数据按指定规则进行修改,最后将数据返回给网络库,传递到请求网络的业务方,此方法能有效地降低对基础库的侵入性能。

    SDK的特点:

    泛用性广:移动端有各种不同的网络库在使用,把拦截网络库的功能独立成一个library并适应不同开发团队的技术场景,目前已落地到多个业务线。

    非侵入式对接:各业务线通过该SDK对接网络库进行数据拦截,原有网络库无任何侵入式修改。

    缺陷管理:在业务方使用“脏数据”的过程中发生异常崩溃,SDK自动捕捉异常信息并投递缺陷给模块的负责人,测试任务将重启APP继续测试流程的循环。

    三、测试驱动方式

    SDK开关打开后,运行我们的测试应用服务,就可以在APP的UI页面上进行操作。操作方式包括:自动化测试、稳定性测试、手工测试。

    自动化测试(UI自动化)

    我们使用UI自动化作为主要的驱动方式之一,UI自动化可以精准到达被测页面,并进行指定场景接口的返回数据替换测试。
    在这里插入图片描述

    针对健壮性测试的UI自动化,无需复杂的步骤,在达到指定页面后,重复触发接口请求。此驱动方式具有编写便利、维护成本低的特点。当被测页面接口返回数据量级较大时,需要耗费较长时间才能达到数据高覆盖的目的,UI自动化无需值守可以极大降低人力投入。

    此方式适用于回归测试、大量数据页面、性能压测等测试场景。

    稳定性测试(Monkey类测试)

    为了让APP混沌测试覆盖更广,我们将“脏数据”修改方案在稳定性测试中进行实施 , 以低成本实现多页面触达的需求,触发更多页面的后端接口。默认使用全量字段随机注入。

    以下是处理逻辑:
    在这里插入图片描述

    根据预埋或者自定义的页面层级访问权重,对APP中的页面进行随机访问。在APP启动且进入预期页面之前打开SDK开关。为了提高修改频率,可以在进入目标页面后适当加入刷新操作(可配置)。期间如触发崩溃问题,则通知SDK侧进行日志提取和缺陷提交,随后关闭SDK,进入下一个循环。

    手工测试

    特点优势:具备灵活度高、成本低,针对自动化难以涉及的扫码、支付等多种场景;

    使用场景:在开发准入、新功能测试中落地,针对新增接口节点进行充分验证;

    执行流程:配置策略>安装APK>进入启动页>填写策略ID>进入被测页>缺陷分析>自动缺陷管理。

    04效果收益及未来规划

    目前,该技术方案已经推行到多个业务线,在测试过程中召回多个难以发现的缺陷,帮助规避了线上可能出现的崩溃问题;新业务新场景接入便捷,落地投入成本较低,自动化任务几乎零维护;缺陷闭环率达50%以上,有效提升代码的健壮性和稳定性。

    未来,团队计划增加更丰富更多变的服务能力,包括:

    1)提升数据节点覆盖的广度和深度;

    2)丰富“脏数据”类型与内容形态;

    3)接口迭代场景精准匹配,支持数据自动提取解析,针对性测试;

    4)支持多台设备并发执行策略的能力,实现分布式数据遍历修改。

    在这里插入图片描述

    这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴我走过了最艰难的路程,希望也能帮助到你

    关注我的微信公众号【伤心的辣条】免费获取~

    送上一句话:

    世界的模样取决于你凝视它的目光,自己的价值取决于你的追求和心态,一切美好的愿望,不在等待中拥有,而是在奋斗中争取。

    我的学习交流群:902061117 群里有技术大牛一起交流分享~

    如果我的博客对你有帮助、如果你喜欢我的博客内容,请 “点赞” “评论” “收藏” 一键三连哦!

    好文推荐:

    转行面试,跳槽面试,软件测试人员都必须知道的这几种面试技巧!

    测试岗反复跳槽,跳着跳着就跳没了…

    软件测试人员该学习 Python 的七个理由

    App公共测试用例梳理

    面试经:一线城市搬砖!又面软件测试岗,5000就知足了…

    35岁之后软件测试工程师靠什么养家?我能继续做测试!

    以上是关于爱奇艺iOS稳定性测试实践的主要内容,如果未能解决你的问题,请参考以下文章

    爱奇艺移动端APP健壮性测试的设计与实践

    奇艺iOS移动端网络优化实践 | 请求成功率优化篇 原创 Charles 爱奇艺技术

    爱奇艺iOS移动端网络优化实践 | 请求成功率优化篇

    爱奇艺 Flutter 跨平台 Hybrid 实践

    爱奇艺开播助手Flutter跨平台Hybrid实践

    爱奇艺技术分享:爱奇艺Android客户端启动速度优化实践总结