动手点关注 干货不迷路
在 Apple 对 TestFlight 限制以后,单 App 通过 TestFlight 渠道灰度用户总量受限,灰度暴露稳定性问题的能力受到极大的限制,如何能更好地在线下暴露更多的问题,成为当前最棘手的问题。
Fastbot 是公司 Quality Lab 与 GIP - iOS 平台架构团队共同研发的智能化测试服务,其利用机器学习和强化学习进行遍历测试,其提供了基础的稳定性测试服务能力,在代码覆盖率和稳定性测试方面,都有着比传统 Monkey 更好的效果,问题发现数及代码覆盖率都有一倍以上的提升,在代码覆盖率方面与人工回归有着相当的表现。[1]
GIP - iOS 平台架构团队从 2020 下半年就开始投入到 Fastbot 落地相关工作中,结合业务测试痛点及落地期间遇到的测试问题,我们主要从以下 3 个方面进行了探索和实践:
Fastbot 通用能力开发,比如 Fastbot 操作可视化、Fastbot 卡屏检测;
Fastbot 能力拓展,这个主要是在被测 App 端内做一些业务定制能力,比如场景限定、通用 UI 检测、键盘场景优化等;
Fastbot 数据消费,比如线下准出流程的建设、测试机时分配策略的探索;
基于上述 3 个方面的实践,我们当前建立了一套基于 Fastbot 的自动化测试流程,从问题发现到消费形成完整闭环,持续保障被测 App 的稳定性。此外,针对每一个 MR 的改动,我们接入精准定向测试流程,其利用代码仓库构建了代码模型,根据 MR 的代码变更获取到受影响的关联 VC,结合 Fastbot 历史测试经验集,定向的测试关联 VC 对应逻辑,期望真正实现“改哪里测哪里”。
为进一步提升 Fastbot 的遍历能力和问题发现能力,使其可以覆盖到更多的 ViewController,对于入口较深的 VC, 由于 Fastbot 测试的随机性,其很难一次遍历到此类的 VC,且无法保证在此类 VC 页的测试时长,针对此类问题我们设计实现了场景限定的功能,可以保证其在在某个支持 scheme 跳转的 VC 中持续测试。
其核心逻辑是在动态库中搭建了一个 WebServer 服务用于和 Fastbot 进行通讯,且内部 Hook 了 UIViewController 的 Present 和 Push 相关的方法,监听 VC 进入和退出的逻辑。
当 Fastbot 通过配置文件获取到需要定向的 scheme 后,会调用 checkin 接口,将需要跳转的 scheme 传递给被测 App,被测 App 在获取到限定的 scheme 后,根据当前限定的状态(正在跳转中、跳转成功、退出定向等)来完成相应的限定逻辑。
如果当前 scheme 可以限定时, 被测 App 通过业务自己实现的路由逻辑完成跳转(或通过 OpenUrl 的形式来实现跳转)。当到达限定页面后,Fastbot 会在每次 Action 操作时触发 isLimit 请求,在被测 App 内获取当前页面堆栈,判断 VC 是否在限定场景中,如果已经跳出限定场景,则 Fastbot 会重新拉起需限定的 scheme。
同时当 App dismiss 或者 pop 出当前 VC 时,被测 App 也会触发检测逻辑,如果当前内存 VC 栈中已经没有限定 VC 时,被测 App 会请求 Fastbot 的 jump_out 服务,当 Fastbot 收到该请求后,会再次触发 checkin 请求,调起限定场景。
场景限定功能落地后,简化了特定 VC 限定测试的流程,现广泛应用于各个活动场景测试,有效异常拦截率从不足 5% 提升至 20% 以上,保障了各个活动的平稳上线。
目前我国有 1700 多万视障人士,其中智能手机用户占比 92%,都有比较强烈的移动应用使用诉求。但是在这些视障用户使用移动应用的过程中,满意度整体较低,非常满意的只有 18%(数据来源:[2])。
为了更好地服务于视障人士,前期我们已经做了很多的工作,但随着需求的不断迭代,每一个新功能的上线都必将伴随着一个新的无障碍适配工作的诞生,甚至之前已经完成适配的部分也会遭到破坏。因此需要一个完整的无障碍链路来保障 App 的无障碍适配一直保持高可用性。我们采用了 Fastbot 自动化测试,在 App 开启无障碍模式时,测试当前 UI 中未满足无障碍要求的问题,并记录相关问题,上报到服务端。
其核心原理是利用 Fastbot 遍历的过程中,在每一步操作的时候,利用 UIAccessibility 的属性对当前界面利用 Google 的 GTXLib[3]规则进行检测。GTXLib 是 Google iOS 平台无障碍检测的一种工具,其内部集成了 XCTest,可以与任何基于 XCTest 的框架一起使用。
目前 GTXLib 可以检测出以下七大类问题:
Accessibility label punctuation:无障碍标签标点符号;
Touch target size:控件交互大小;
Accessibility label-trait overlap;
Accessibility label:检查所有可访问元素必须具有 Accessibility 标签;
Supports Dynamic Type:文本的 adjustsFontForContentSizeCategory 属性为 YES,进行自动缩放;
Contrast ratio (Label):对比度;
Accessibility traits:无障碍特性,用来告知辅助应用一个无障碍元素怎样行为或者应该怎样被对待。
OBJECTIVE-C
UIAccessibilityTraits UIAccessibilityTraitNone;//该无障碍元素无特性
UIAccessibilityTraits UIAccessibilityTraitButton;//该无障碍元素应该被当作一个按钮
UIAccessibilityTraits UIAccessibilityTraitLink;//该无障碍元素应该被当作一个链接
UIAccessibilityTraits UIAccessibilityTraitSearchField;//该无障碍元素应该被当作一个搜索框
UIAccessibilityTraits UIAccessibilityTraitImage;//该无障碍元素当前已被选定
UIAccessibilityTraits UIAccessibilityTraitSelected; //该无障碍元素当前已被选定
UIAccessibilityTraits UIAccessibilityTraitPlaysSound; //该无障碍元素被激活时播放自己的声音
UIAccessibilityTraits UIAccessibilityTraitKeyboardKey; //该无障碍元素的行为像键盘键
UIAccessibilityTraits UIAccessibilityTraitStaticText; //该无障碍元素应该被当作不能改变的静态文本
UIAccessibilityTraits UIAccessibilityTraitSummaryElement; //当应用启动时,该无障碍元素提供摘要信息
UIAccessibilityTraits UIAccessibilityTraitNotEnabled; //该无障碍元素不可用且不能响应用户交互
UIAccessibilityTraits UIAccessibilityTraitUpdatesFrequently; //该无障碍元素频繁更新其标签或值。
UIAccessibilityTraits UIAccessibilityTraitStartsMediaSession; //当该无障碍元素被激活时,启动一个媒体对话
UIAccessibilityTraits UIAccessibilityTraitAdjustable; //该无障碍元素的值在一定范围内允许持续调整
UIAccessibilityTraits UIAccessibilityTraitAllowsDirectInteraction; //该无障碍元素允许VoiceOver用户直接触摸交互
UIAccessibilityTraits UIAccessibilityTraitCausesPageTurn;//该无障碍元素应该引起自动翻页,当VoiceOver阅读完成当页的文本时
UIAccessibilityTraits UIAccessibilityTraitHeader;//该无障碍元素是一个将内容划分为章节的标题,例如导航栏的标题
在每次用户 touchBegin 屏幕的时候进行检测,GTXLib 会对所有 Window 进行遍历,将所有不符合无障碍规则的 case 封装到 GTXResult 结构中,并上报到服务器。
目前头条已经建立了 Fastbot 无障碍测试任务,旨在帮助 QA 和 RD 快速发现当前 App 内未满足无障碍要求的 case 并进行修改,其检测效果如图所示:
在分析 Daily 任务中我们发现有 2 类常见问题会影响到 Fastbot 的遍历能力:被测 App 长时间卡住和键盘场景不退出。为解决这两类异常问题,我们设计了卡屏检测和键盘聚合限频方案。
在 Fastbot 测试过程中,经常遇到被测 App 进入某些场景出不来的情况。一个 10 小时的 Fastbot 任务可能后面 7-8 个小时都处于下面这种卡屏状态,这对 ByTest 测试机时是一种很大的浪费。如下图,进入视频页后卡住。
之前解决这种卡屏的问题,一般是找到对应的场景,再去分析卡住的原因,针对性地进行处理,但是这样的处理周期会比较长,不能及时止损。这里我们在 Fastbot 内部实现了卡屏检测逻辑,如果识别到页面卡住超过一段时间,则会触发 Fastbot 的卡屏检测逻辑。
卡屏检测是基于 sid 来做的,Fastbot 会对每一次的页面树做一次类似 md5 的计算,生成一个场景的唯一标志, 这就是 sid。在一次操作结束之后比对历史的 sid 值,从而判断是否卡屏,最简单的方式是,比如连续十次的 sid 都是一样的,则认为页面卡住了,但是有时可能是两个页面反复横跳,sid 在变了,这种其实也是卡住的。针对这个问题我们的解决方案是,统计最近 30 次的 sid,如果其中占比最高的 sid 超过 87.5%(经验值),则认为此时需要触发卡屏处理流程。
Fastbot 内部的卡屏处理流程依次是:强制返回、处理系统弹窗、处理被测 App 内部弹窗、强制重启被测 App。
该逻辑上线后,整体减少 10% 的测试机时浪费,同时为了后续能去分析卡屏的具体原因,当触发强制重启 App 时,会同步记录相应日志,到任务结束时,会触发一个任务分析程序,结合日志列出具体的卡屏页面供 RD 分析排查。
在实际测试中,通过分析测试任务,发现当 Fastbot 进入到键盘后,会在较长的一段时间内停留在键盘输入,同时一次任务中又会存在多次调起键盘操作,这会导致测试中键盘时长占比过高,影响了 Fastbot 的遍历效率,减弱问题前置发现的能力。
针对该类问题,分析键盘场景下的 UI 视图树结构,优化键盘控件,从 UI 视图树可以分析出键盘中每个键都是一个独立的控件,而算法侧的策略是尽可能地遍历每一个控件,这会极大地增加键盘点击的次数。因此在 Fastbot 获取页面元素树时对键盘上的控件进行聚类,在获取到页面结构数据时,根据节点信息中的 "KBKey" 或者 "UIKeyboardEmoji" 等标识,对这些控件的 resource_id 等属性做聚类处理,将键盘上所有控件聚合成一个控件进行操作,降低点击键盘的几率。
此外在头条 Feed 评论场景,点击全屏后,键盘及输入框占满整个屏幕,如下图所示。该场景中,虽然将键盘聚合为一个控件,但是点出键盘的操作路径较深,难以完全解决。针对此类 case,我们从客户端视角进一步的优化键盘场景,对键盘出现的次数和使用时长都进行限制,在一次生命周期内最多运行出现 5 次键盘,并且每次键盘使用时长不超过 3 分钟,如果超时未销毁键盘时,直接销毁键盘,同时根据右上角坐标获取 keyWindow 的第一响应者,如果第一响应者存在 Tap 手势, 则触发 Tap 的响应逻辑,模拟实际用户操作来跳出该场景。
该项优化上线后,一次 10 小时的单机测试任务,键盘出现的时长占比从 20% 优化至 5% 以内,有效解决了测试任务中键盘对整体测试任务的影响,提高了非键盘场景的测试时长。
前面我们主要阐述了在提升 Fastbot 测试能力方向探索和实践的一些方案,对于拦截到的问题,我们同样做了一些探索,用于快速消费稳定性问题,并给准出标准和判断依据,整体来辅助 RD 进行准出决策,优化准出效率。
前期围绕 Fastbot,我们建立了很多指标,如召回率、覆盖率、 线下 crash 异常率、机时完成率等等,每个指标都有各自的适用范围, 但是这些指标过于分散,也没有主次,不能直观反映某个版本的质量水平,为版本准出提供依据。比如线下 crash 率低,说明版本质量好,但是如果是因为 Fastbot 本身出了问题,没有测出 crash 呢,所以还要综合考虑 Fastbot 的 VC 覆盖率才能得出结论。因此我们做了一套线下准出流程来解决指标判断困难的问题。
现在线下准出流程由三部分组成:
第一部分是质量评估,也是最核心的部分,用于反映 App 的质量;
第二部分是异常消费,就是发现并解决问题;
第三部分是准出卡口,用于发版时确认产品质量。
整体流程如下:
该流程整体上线后,共辅助了 GIP 侧 10 个版本的准出上线,整体优化 2 人日。
以头条的稳定性测试结果和业务收益为目标,从测试策略、研发流程等层面进行建设相关的线下测试流程。目前我们每天自动构建主干分支包并用于测试,异常问题召回率从最初的 19.1% 提升到了现在的 45.76%(双月 Fastbot 发现的已修复问题数/双月已修复问题总数),当前可达 VC 覆盖率(Fastbot 测试覆盖 VC 数/线上用户触达 VC 数)为 80% 左右。
因 Fastbot 精准定向测试在 GIP 侧仅测试 Feature 类 MR 中有 VC 变更的需求,其在 2021.12.15 至 2021.12.22 一周内的执行率为 53.03%(执行测试 MR 数量/变更 MR 数量),受测试时长和 VC 是否关联 scheme 的影响,定向测试的平均关联 VC 覆盖率(测试中覆盖 VC 数量/ MR 关联 VC 数量)为 42.95%,其中已覆盖的关联 VC 停留时长占比 46.69%,双月修复率 15.38%(双月定向测试发现的已修复问题/双月定向发现的总问题)。从当前修复率可以看出,精准定向已经可以在 MR 阶段提前拦截一部分稳定性问题,但还有着较大的提升空间。
目前 Fastbot 自动化任务已经能较好地发现 App 内的稳定性问题,已经可以帮助头条拦截 50% 左右的异常问题。此外,我们将持续完善 Fastbot 的遍历能力和健全 Fastbot 相关指标建设,如行覆盖率等。同时联动线下录制回放,将核心测试 case 录制入库,结合定向算法,最大程度还原录制操作行为的同时进行场景内发散性测试、全方位的测试。特别是对于 MR 级别的改动,在测试稳定性的同时,不断完善 UI 断言及性能测试能力,整体全面地完成自动化测试,降低人力测试成本。
附录
[1]奔跑吧!智能 Monkey 之 Fastbot 跨平台
[2]中国互联网视障用户基本情况报告
https://www.siaa.org.cn/static/image/img_media/%E4%B8%AD%E5%9B%BD%E4%BA%92%E8%81%94%E7%BD%91%E8%A7%86%E9%9A%9C%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E6%83%85%E5%86%B5%E6%8A%A5%E5%91%8A.pdf
[3]https://github.com/google/GTXiLib
我们作为今日头条平台架构 iOS 团队,在性能优化、基础组件、业务架构、研发体系、安全合规、线下质量基础设施、线上问题定位归因平台等方向持续深耕,负责保障和提升今日头条的产品质量和开发效率,聚焦于今日头条的同时向外延伸。
如果你对技术充满热情,喜欢追求极致,渴望用自己的代码改变数亿用户的体验,欢迎加入我们。我们期待你与我们共同成长。目前我们在北京、深圳均有招聘需求,简历投递邮箱:[email protected];邮件标题: 姓名 - 工作年限 - 今日头条 - 平台架构 - iOS/Android。