GrowingIO 是基于用户行为数据的增长平台,精准采集用户行为数据是公司业务的基石,只有及时、准确、可靠的采集到数据,才能支撑上层的数据分析,用户画像,运营等业务,所以公司一直非常注重数据采集 SDK(Software Development Kit) 的质量保证工作。
为了满足客户的各种业务与技术的需求,GrowingIO 提供了 Web、Android、 iOS、Hybrid、各种小程序(微信、支付宝、头条、QQ 等 )、微信内嵌页等多种平台,以及 React Native、Flutter 、Cordova、Weex 、API Cloud 、AppCan 众多开发框架的 SDK,这无疑为 SDK 的测试工作带来的巨大的挑战。
本文主要介绍 GrowingIO 在 iOS SDK 测试方面的具体实践,希望对从事 iOS 测试的同学提供一些参考。
1. 数据采集 SDK 是如何工作的?
要测试一个软件或系统首先必须要先了解其业务逻辑和技术实现,接下来我们简单看下数据采集 SDK 是如何工作的。
GrowingIO 的数据采集 SDK 支持无埋点(全埋点)数据采集以及埋点数据采集,以满足不同的业务需求,其简易结构如下:
在用户打开 App ,浏览不同的页面,点击不同的元素(如按钮,文本框,图片),关闭 App 时,无埋点事件采集模块会将用户的具体行为自动采集并保存到手机的本地存储(关于无埋点数据采集的具体实现,欢迎关注 GrowigIO 后续的文章分享,这里不再详述)。
埋点事件采集与之类似,不同之处是埋点事件是由 App 主动调用 SDK 的埋点 API 触发事件采集,当然不同事件的具体数据格式有所不同。
接下来是数据发送模块,其主要负责将数据通过 HTTP API 上报到数据接收服务。
需要说明的是,为了节约用户的数据流量和电量,发送程序并不是实时上报的,它会根据设备的电量、网络类型、以及数据量进行发送时机的选择,而且发送前还会对数据进行压缩和混淆以降低传输数据量并提升数据安全性。
当然数据发送程序还会处理数据上报中的各种数据发送失败,网络异常等错误,采取适当的重试机制。
2. 如何测试?
通过以上结构分析,可以看出数据发送模块跟核心的数据采集业务关系不大,并且很稳定,几乎不会改动,因此我们测试的重点主要是数据采集部分,尤其是无埋点数据采集。
要测试数据采集首先需要有一个包含各种页面和元素的 Demo App,然后切换不同的页面,操作页面上的元素或触发埋点事件,然后检查采集到的事件数据是否正确。
检查事件数据有两种方式,一种是将事件详细数据通过日志打印出来观察日志检查;一种是通过抓包程序获取数据发送然后检查。
后者一般需要配置复杂的代理工具,而且数据量多,还需要考虑数据的解压缩、解密,比较难以精准定位到事件数据。所以在实际测试中一般使用前者。
上图是一个采集数据的日志截图,通过图中的事件数据我们发现,其字段众多,且一些字段可读性不高,人工检查耗时较长。
此外 SDK 数据采集的主要逻辑基本不变,但是每次修改都必须进行足够的回归覆盖,以免遗漏错误。
一旦遗漏了缺陷到线上,其造成的损失是极其昂贵的,即使在后续版本修复了缺陷,其造成的影响也很难消除,因为移动端 App 的升级周期是很难控制的。
在加上 GrowingIO 数据采集 SDK 兼容 iOS 8 及以上版本,需要对各个版本系统做兼容性测试,其测试工作量显而易见。
幸运的是 SDK 的业务变化很少,断言内容比较机械,特别适合自动化测试。而且回归测试工作量巨大,采用自动化测试可以极大的提升生产率和质量。
3. 选择测试框架
工欲善其事必先利其器,开展自动化测试之前必须选择一款合适的自动化测试框架。选择框架的时候有几个方面要考虑:
- 开发的成本(支持语言,是否可调试,代码补全)
- 维护成本(框架的稳定性)
- 是否需要源代码
- WebView 的支持(很多App都用到了H5)
- 对操作系统,开发工具的支持情况( 是否支持 iOS 8)
- 测试用例执行效率
- 测试报告(截图,代码覆盖率,…)
- 是否支持CI(持续集成)
- ……
当前支持 iOS UI 自动化测试的主要框架对比如下:
考虑选择测试框架的几种影响因素。
首先,使用的语言和框架决定了测试人员的持续性学习成本,iOS SDK测试人员对 Objective-C 熟悉和掌握程度高,不需要消耗额外的学习成本,测试与开发同一技术栈。
其次,测试 App 程序根据需求时有调整,使用开发效率高、调试方便的测试框架能使我们在适应新 UI 变化、新需求时获得更小的投入产出比。
综合以上考虑,KIF 框架已经展现了他的优势,并且 KIF 使用 XCTest 框架,使得其测试流程 iOS 程序的单测无异,可完全复用单测的持续集成流程,维护持续集成的成本相对降低;另外,KIF 是一个活跃的开源测试框架,可扩展性好,升级更新快,有活跃社区来探讨和解决使用过程中遇到的问题。
鉴于上述优势,我们选择了 KIF 作为 iOS 的 UI 自动化测试框架。
KIF 的全称是 Keep it Functional,它是一个建立在 XCTest 的 UI 测试框架,通过 Accessibility 来定位具体的控件,再利用私有的 API 来操作UI。由于是建立在 XCTest 上的,所以你可以完美的借助 XCode 的测试相关工具。
4. 自动化测试的实施
语言与工具
- 语言:Objective-C
- IDE:Xcode
- 测试框架:KIF
搭建测试环境
- 在现有工程中添加 Target 实现,选择 File → New → Target… 菜单项,从中选择 iOS → Test 中的 UI Testing Bundle 模板,如下图所示:
- 单击下一步,进入 Target 选项页面,设置测试工程相关项
- Product Name: KIF 测试工程名,可以自由命名,最好是测试工程名 "Tests"。
- Organization Name,Organization Identifier,Bundle Identifier,根据需要自行命名即可。
- Language: 编码语言,有 Objective-C 和 Swift , 根据需要选择,我们使用的是 OC。
- Project 和 Target to be Tested:为对应的要测试的工程名,一定要保证是正确的。
- 完成 Target 设置后,点击「Finish」按钮,创建成功。
- 安装 pod,在命令行终端输入以下命令。
sudo gem install cocoapods
- 修改或创建工程的 pod 文件 Podfile。
target 'GrowingIOTest' do pod 'SDCycleScrollView', '~> 1.75' pod 'MJRefresh' pod 'MBProgressHUD'end target 'GIOAutoTests' do pod 'KIF','~> 3.5.1'end
其中如下一段内容为新添加的
代码语言:javascript复制target 'GIOAutoTests' do pod 'KIF','~> 3.5.1'end
- 在项目目录中执行以下安装命令, 安装相应的依赖,测试项目准备完成。
pod install
- 准备好被测程序,在测试 Demo 项目中集成需要被测试版本的数据采集 SDK。
编写测试用例
测试环境搭建完成后,接下来就是编写具体的测试用例了,一般测试用例的主要步骤为:
- 准备测试环境
- 执行测试步骤
- 测试结果断言
- 测试结果报告
- 清理测试环境
下面以 SDK 的无埋点元素点击事件自动化测试用例为例,说明自动化用例的编写。
测试用例:
启动 App,模拟用户滚动屏幕找到对话框按钮,然后点击对话框按钮,显示对话框后点击关闭按钮, 校验点击事件发送数据,发送内容正确。
代码实现:
代码语言:javascript复制- (void)setUp { // 一些初始化操作}-(void)tearDown{ // 一些结束动作}-(void)testDialogBtnCheck{ /** function:对话框按钮点击,检测点击事件, **/ [[viewTester usingLabel:@"UI界面"] tap]; //添加向下滚动操作 [tester scrollViewWithAccessibilityLabel:@"CollectionView" byFractionOfSizeHorizontal:0.0f vertical:10.0f]; [tester waitForTimeInterval:1]; [[viewTester usingLabel:@"LabelAttribute"] tap]; [[viewTester usingLabel:@"ShowAlert"] tap]; [tester waitForTimeInterval:1]; [[viewTester usingLabel:@"取消"] tap]; [tester waitForTimeInterval:3]; NSArray *clckEventArray = [MockEventQueue eventsFor:@"clck"]; //是否发送clck事件 if(clckEventArray.count>=2) { //判断点击事件是否字段发送正确 NSDictionary *chevent=[clckEventArray objectAtIndex:clckEventArray.count-1]; NSDictionary *clkchr=[NoburPoMeaProCheck ClckEventCheck:chevent]; //NSLog(@"Check Result:%@",clkchr); XCTAssertEqual(clkchr[@"KeysCheck"][@"chres"], @"Passed"); NSLog(@"对话框按钮点击,检测clck事件测试通过---Passed!"); } else { NSLog(@"对话框按钮点击,检测clck事件测试不通过:%@!",clckEventArray); XCTAssertEqual(1, 0); } }
由于我们主要测试 SDK 的功能,测试 Demo 是我们自己设计的,主要覆盖各种 UI 元素和事件,其业务逻辑比大多数的业务类型 App 都简单,没有什么特别介绍的。
这里介绍下断言的设计。前文介绍过,我们自动化测试的重点是数据采集规则正确,不关注数据存储与发送。
SDK 在采集数据时会将所有事件先加入一个队列,然后再保存到 DB,所以在执行测试时,只需要监听事件队列,即可在监听的事件队列中按照需要保存和获取需要断言的事件。点击事件发送的数据结构大致如下:
对事件数据的校验,首先保证字段完整且每个字段不为空,即数据的 Schema 正确;其次根据需要对事件的具体字段做校验,比如点击事件的类型 t 应该为 clck 。这些检查被封装到了单独的 Check 方法中,如果检查通过则方法返回 Passed。
这里是通过 ClckEventCheck 方法完成了具体的业务校验。
执行测试用例
主要介绍下如何通过命令行执行测试。
安装 Command Line Tools(命令行工具包),App Store 安装 Xcode 默认不会安装 Command Line Tools,可以通过在命令行输入以下命令进行单独安装。
代码语言:javascript复制xcode-select --install
在使用命令行执行测试之前,还需要将项目设置成 Shared。打开 Product → Scheme → Manage schemes,查看项目是否是 Shared,如果不是,则选中后面的复选框将其共享。
命令行执行所有的测试用例
代码语言:javascript复制xcodebuild -workspace Growing.xcworkspace -scheme GrowingIOTest test -sdk "iphonesimulator13.5" -destination platform='iOS Simulator',OS=13.5,name='iPhone 11'
执行单个用例
代码语言:javascript复制xcodebuild -workspace Growing.xcworkspace -scheme GrowingIOTest test -only-testing:GIOAutoTests/ClckEventsTest/test7DialogBtnCheck -sdk "iphonesimulator13.5" -destination platform='iOS Simulator',OS=13.5,name='iPhone 11'
更多 xcodebuild 的使用方法可以参考其使用说明。
代码语言:javascript复制man xcodebuild
美化测试报告
xcodebuild 的输出阅读起来不是太直观,使用 xcpretty 可以解决这个问题,并且它还能完成测试报告生成。
xcpretty 是一个高速灵活的 xcodebuild 输出格式化工具,其使用如下:
代码语言:javascript复制# 命令行安装 xcprettygem install xcpretty
命令行执行
代码语言:javascript复制xcodebuild -workspace Growing.xcworkspace -scheme GrowingIOTest test -sdk "iphonesimulator13.5" -destination platform='iOS Simulator',OS=13.5,name='iPhone 11' | xcpretty --report html
生成的测试报告如下:
默认输出 html 报表在 build/reports/tests.html
5. 覆盖率统计
在执行自动化测试的时候,通常我们想获取测试覆盖率报告,以度量自动化测试的覆盖情况。因为 KIF 是直接基于 XCTest 实现的,所以可以很容易地使用 Xcode 自带的覆盖率统计工具。其设置如下:
Product → Scheme → Edit Scheme,Code Coverage 把需要统计覆盖率的被测程序加入到 Targets 中。
测试完成后可以拿到覆盖率统计报告。
6. 持续集成
自动化测试的最大价值在于可以替代人工进行更高效、更频繁的测试。因此要发挥自动化测试的价值,最理想的方案是,将自动化测试加入到持续集成环节中,每当有代码变更时,就自动的执行测试,快速反馈结果。
我们利用 Jenkins 监控代码仓库变更,当有新的 commit 提交时,Jenkins 会自动拉去最新的代码,并调用命令行执行相应的自动化测试用例,收集相应的测试报告,并将测试结果通过钉钉机器人及时的通知给相关的开发和测试人员。
当测试失败时,相关人员可以第一时间收到结果,并及时解决。
7. 总结
本文以 iOS 平台为例系统的介绍了 GrowingIO 数据采集 SDK 主要工作原理,测试方案的设计以及自动化测试框架的选型与自动化测试实施。希望对从事 SDK 测试工作的同学有所启发。
后面我们还会分享 GrowingIO 用户触达 SDK 的自动化测试,Android SDK 自动化测试等相关的内容,请大家持续关注我们。