主题测试自动化:Fastlane篇
Contents
行文的主要目的是展示如何用fastlane工具,做多主题在多设备上的测试任务,所以不会对fastlane做全面系统的介绍。但如果在自动化任务中用到fastlane相关技术点,重要的细节、坑或者最佳实践,会在相应的步骤特别的说明。
文章大纲
- Fastlane概述,包括fastlane的前世今生
- 如何使用Fastlane实现主题测试自动化,步骤分解
- 定制输出结果,编写Fastlane的action
- Fastlane使用的注意事项
1. Fastlane概述
Fastlane 作者Felix Krause,于2014年创造了fastlane项目,一年后的2015年被fabric收购,在此之前的2014年,fabric被Crashlytics收购,而Twitter则在2013年收购了Crashlytics。自2015起,作者一直在Twitter开发fastlane,直到2017年Google收购了fabric,现在在Google全职开发fastlane。 从履历上看,fastlane的背后有强大的公司支持和实践,近年来发展势头很好,更新迭代很快。(在前段时间iTunes更改了后台登录的验证方式之后,fastlane团队第一时间获取信息,发布了公告,并在一周内fix)。
fastlane内置了很多常用的actions,如snapshot、deliver、gym
等,可以满足大部分场景下的需求,详细用法可在官网查看。
事实上,我们可以自己编写actions,那么fastlane内置的actions和我们自定的actions有没有区别呢?
fastlane内置的action的特殊之处
- fastlane内置的action,可以直接在命令行里直接运行,如
fastlane snapshot
,而自定义的action,如后文提到的resort_screenshot
,如需在命令行运行,需要使用语法fastlane run resort_screenshot
- 内置action有相应的配置文件,如snapshot相应的Snapfile,定义了action需要的参数。(事实上fastlane本身也有一个配置文件Fastfile)
- 假设,你在Fastfile(fastlane的配置文件)里创建了一个和内置action重名的lane如
snapshot
,则fastlane snapshot
命令读取到的是内置action,而不是作为lane的snapshot
和actions相关了两个命令,如下:
|
|
Fastlane本质上是一系列符合Fastlane规范工具的执行环境。这些工具处于fastlane的管理之下,可以使用fastlane的全局变量、credentials_manager、上游action的输出等数据。fastlane对编写action时,经常使用的组件或util,做了简单的封装,使每个action的行为表现保存一致。如在控制台输出错误提示信息时,可以使用以下语法
|
|
每个lane执行完毕,在控制台都会有相应的统计数据,样式完全一致。fastlane是ruby的一个gem——为了定制自己的actions,你需要了解ruby的基本使用。
如果需要了解详细的关于fastlane的信息,请访问官网docs,Getting started with fastlane for iOS
2. 主题测试自动化步骤
2.1 安装fastlane
确保安装了ruby,版本在2.00以上。假设按照fastlane官网的步骤,你已经成功安装fastlane。
注:如果安装过程里出现了错误,fastlane在输出错误信息的同时,很智能的会在open或者closed的github的issues查找相关的解决方案,输出在console里,供我们fix时做参考。
之所以,fastlane能够智能的提供错误解决方案,得益于fastlane对github上issues
的良好管理,当向fastlane的github工程里提issue时候,github的机器上fastlane-bot
会提示你请提供fastlane env
在本机上的输出结果。这是个非常非常聪明的作法,利用众包的方式发现问题、解决问题。李飞飞的ImageNet的诞生也离不开众包,进行有监督的学习。
2.2 初始化fastlane
在.xcodeproj
文件所在的文件夹下执行
fastlane init
会在当前目录下生成一个/fastlane
的文件夹。此后所有的fastlane相关文件都会在此文件夹下。
本流程不需要app_identifier、apple_id、team_id
的数据,所以不需要Appfile,此处略过。
在生成的文件里,其中最重要的是Fastfile。打开Fastfile文件,定义自动化测试的任务,起名叫test_ui_test
,核心代码如下,
|
|
有了入口文件,参考fastlane的各类接口,调用相关actions,如snapshot等内部action,结合普通的ruby语句,我们就可以开始实现自动化截图任务逻辑了。 ###2.3 主题测试后自动化需求和方案
1. 需求说明
有钱的iOS2.7.5增加了主题功能,用户可以选择自己喜欢主题,主题数量大概有7种,在制作过程中,发现需要适配iPhone6、iPad、其他iPhone,3种不同的设备。所以我们需要对7 * 3 = 21
种情况来检查皮肤是否显示正常(暂时不考虑多语言)。
在测试过程中,除了需要切换不同主题外,还需要切换3种设备;加上主题的配色其实还在迭代中,一旦改动又需要重复的走一遍流程,这个流程对QA而已机械重复而无趣。
所以,我们的目标是如何自动化这部分工作。
2. 思路
多设备适配,可以通过指定snapshot的配置参数devices = ["iPhone 5", "iPhone 6", "iPad Air"]
来实现。那如何定义多主题测试呢?总不能默认执行所有皮肤吧——我们需要开始运行时,指定本次测试需要测试哪些皮肤。根据项目情况,决定用主题的服务端配置的id来标示(themeServerId)需要测试哪个皮肤,并且themeServerId有一个对应关系。如下表格
主题serverId | 主题名称 |
---|---|
001 | 粉红物语 |
002 | 月宫玉兔 |
003 | 海底世界 |
004 | 缤纷几何 |
005 | 宁静夏夜 |
最终方案是:在执行fastlane 命令的时候去指定主题id,可以指定多个主题,这样就可以实现测试多个主题。但是这个方案遇到一个难题——如何在命令行传参数给app传值。
为什么会采用这种方案?
2.1 有钱的主题的更新机制。
有钱的主题是通过用户在界面选择主题类型,代码里触发
|
|
来实现皮肤的下载。
2.2 fastlane工具链流的限制。
在输入了命令fastlane test_ui_test
后,fastlane去调用XCUITest,然后XCUITest启动有钱的APP(重要的一点,XCUITest只是对有钱APP的代理),在XCUITest运行阶段,只有受限的接口去和APP交互;运行前,更不能直接调用ThemeCacheManager的方法。 而且fastlane和XCUITest之间也无法通讯。
2.3 在翻阅了大量fastlane相关资料,、XCUITest相关API资料、启动APP相关资料,发现snapshot
的参数里有个宝贝——launch_arguments
.
|
|
snapshot的configuration file即SnapshotHelper.swift
获取到snapshot注入的launch_arguments
参数,并且在XCUITest启动的时候设置APP的启动launch_arguments
。然而XCUITest却拿不到这个参数,但是通过XCUITest启动的APP,却是可以拿到的——是Session级别的NSUserDefaults数据。使用下列的语句获取传入的themeServerId。
|
|
在APP的首页拿到这个参数,那么就可以在内部使用这个参数来调用下载皮肤的接口,
|
|
注意:在XCUITest里需要处理下载皮肤的等待。
OK,从fastlane的内置action,snapshot传值给有钱APP的路走通了,如何在fastlane的命令行,传值给snapshot的调用参数呢?比如,我们输入themeServerId
变量是终端里,而不是去每次去修改Fastfile里的参数launch_arguments
。
经过一番搜寻,在fastlane.tools
的advanced.md模块找到了答案。fastlane/Advanced.md at master · fastlane/fastlane · GitHub。形如,
|
|
就可以传值给snapshot作为调用参数。
2.3 实现test_ui_test任务逻辑(lane)
1 编写Fastfile文件。
在lane :test_ui_test
里编写逻辑——获取themeServerId 、需要测试设备类型,2个参数,然后将获取的参数传入 内置action之snapshot,最后打开截图的summary界面的逻辑。相关代码略过。
2 编写截图的逻辑。
在UITests.swift
文件里编写截图代码。包括截图内容、截图顺序。
良好配置的测试用例,可以减少测试次数,优化测试方案,节省时间
按照需求,需要截取6个关键界面,但前提是需要先下载到某个主题——解决方案:可以通过触发下载后,等18s来完成。 另外,在正在进入第一个关键页面,即首页前,可能会有新手引导的一系列界面出现,所以需要排除掉新手引导的干扰。
3 对截图的分组展示和区分。 使用默认的截图总览界面,你会发现多次截图都混着一起,浏览的交互方式也很差劲,看起来很不方便,如图;
所以需要一个更好的交互方式、界面组织方式,经过一番思索。对现有的结构做了如下改进
- 每次测试后的截图为一组,而且默认一组的展示不需要左右滑动。需要查看所有图片的时候,可以弹窗展示,不需要横向纵向滚动条。
- 多次截图,按照先后顺序,向下排列,避免出现左右滚动条。
- 当皮肤数量很多时,可以在纵向扩展,通过竖向滚动,即可浏览全部截图。
这就意味着需要自己定制。所以,决定开发一个action实现上述功能。按照官网的步骤,编写resort_screenshot
的action,这个后面会详细讲到逻辑实现。这里只需要明白一点:
resort_screenshot
对snapshot的截图汇总界面和图片素材做了二次处理
而实现的,并且保留了snapshot原生的汇总界面。所以在lane :test_ui_test
里,执行截图命令之后,接着执行如下代码,
|
|
其中skipOpenSummary表示是否不需要自动打开截图的结果页面。这个选项在测试机上是YES,因为测试是执行完毕之后,会返回一个url,供QA点击在QA本地浏览器打开——并不需要在测试机上打开。
##3. resort_screenshot的action编写
这里需要特殊说明下action、plugin和fastlane的关系。 Action是fastlane里基础的逻辑代码,完成一个特定任务,可以在各个lane的定义里使用,但是只能在内部使用;而plugin则是对action的封装,确定当前action可以依赖的其他plugin的action。功能纯粹,代码良好的plugin可以发布到github之类的地方,供别人在自己的Fastfile里使用。打个比方,
plugin是npm系统里的一个 node_module,而action,可能是node_module里的一个JS文件,是单纯的代码的package
3.1 如何编写action
在命令行输入
|
|
接着输入action的名字,这里我们输入resort_screenshot
,然后会生成
/fastlane/actions/resort_screenshot.rb
打开这个文件,在对应的模板处编写逻辑。
因为resort_screenshot
是对snapshot原来的screenshot
目录的二次处理,所以,在真正开始编写逻辑之前,查看screenshot
目录下的素材结构和展示结果的html(即screenshot.html)的结构。发现这些图都在同一个文件夹,命名是切图序列+自定义文字。另外,还从.gem
这个文件夹下,找到了fastlane的snapshot的源码,其中我们最感兴趣的是生成screenshot.html
。
思考:如何在多次截图的文件夹里,对每一个主题分组呢?这就需要我们知道哪个图片属于哪个主题。换言之,
- 第一步,如何把themeServerId传给XCUITest?
- 第二部,如何把themeServerId传给我们的自定义action-
resort_screenshot
?
前面已经说过,从fastlane端传值给XCUITest是不行的;只剩下从APP里向XCUITest传值。
3.2 APP里向XCUITest传值
经过仔细查找,发现XCUITest可以获取到App UIElement里的label,也就是UIControl 的属性accessibilityLabel
。 所以解决方案是有钱APP在启动后,使用从NSUserDefaults
获取的数据,写到UIControl的accessibilityLabel,然后XCUITest使用
|
|
获取到themeServerId
,作为截图文件的名字的一部分。
3.3 XCUITest向resort_screenshot
传值
正如上述,因为XCUITest获取到themeServerId
,作为截图文件的名字的一部分。所以resort_screenshot.rb
文件读取到图片文件的名字,经过一次循环之后,获取到了分组的类型和数量等数据,包括themeServerId
。
resort_screenshot.rb
可以获取到themeServerId
,传值完成。
注意:XCUITest向
resort_screenshot
传值,传那些数据是密切和业务相关的,同时在resort_screenshot.erb
文件对从XCUITest获取到的数据截取也是业务非常相关的。
后文提供的action的源码其实不是开箱即用的,需要在XCUITest的代码埋数据,在resort_screenshot.rb
截取数据,传递给resort_screenshot.erb
渲染
至此,整个流程就走通了。整体数据的流向图是,
下面演示如何使用。
如何使用
在流程走通之后,需要移交给QA,让他们可以在测试机上测试。在测试机上的Nginx html目录下新增了一个软连接。
|
|
当一个case如命令fastlane test_ui_test themeServerId:002,005 devices:"iPhone 5"
,测试完毕之后,自动打开浏览器,地址形如
|
|
作为对照,你还可以打开snapshot默认的结束汇总界面。
http://youqian.com/screenshot/screenshot.html
就可以看到测试结果了,这个测试结果地址可以给产品、或者视觉,供他们走查。
关于fastlane test_ui_test
的参数
完整的命令如,fastlane test_ui_test themeServerId:002,005 devices:"iPhone 5"
。有两个参数,
- 一个是themeServerId,接受
002, 005
这样的value,表示本次需要截图的主题有哪些,必需参数,这些参数对应前文表格数据,是业务相关,不具有通用性。 - 第二个是devices,表示在哪些设备上截图。选填,默认是iPhone 5,可以是多个,如"iPhone 5, iPhone 6 PLUS"。但不推荐一次性测试多个设备,因为切换iPhone、iPad模拟器比较耗时。
让我们开始吧。我们的目的是测试themeServerId是002,005的两个皮肤的展示是否正确。执行fastlane test_ui_test themeServerId:002,005
,经过一段时间编译之后,会自动打开iPhone 5模拟器,自动截图,结束之后,会在控制台输出类似以下的信息,
当次任务执行的时间统计,这也是fastlane做工具聚合比较有用的一点——它的输出比较美观。并同时打开浏览器,会看到:
每个皮肤的测试作为一个组,以扇形显示。这样不会有横向滚动条。
点击某个扇形里的图片,会打开这张图片,进入大图浏览模式,可以使用左右箭头、或者键盘上的左右按钮来切换图片。
至此,大功告成。
其实为了实现这个功能,中间走了很多的弯路,下一节会集中列出来这些坑,或者某些注意事项,让刚刚接触到的人能够避开。
4.注意事项
- 如果要使用工具链里的match、cert、sign等需要升级openssl到2.0(登录apple developer portal需求)
- 为什么不通过
brew cask install fastlane
来安装呢?通过这种命令安装的fastlane,所引用的ruby版本可能是系统默认的版本,如果你有多个ruby安装在系统上,会遇到很多无法预知的情况 sudo gem install fastlane -NV
之后不一定成功,运行完毕之后,检查出错在哪儿,最常见的错误是ruby版本不对,如果需要多个ruby版本存在,推荐使用rbenv。- Fastfile的写法很灵活,官网上很很多例子供我们参考,可以拿来吸取灵感。
- 细心的读者会发现,其实
SnapshotHelper.swift
是可以拿到snapshot注入的参数,那么我们的主测试代码里也可以拿到的,那为什么说XCUITest和fastlane不能通讯呢? 是的,其实是可以通讯的,但是snapshot注入的launch_arguments
是snapshot自己通过创建了一个中间的snapshot-launch_arguments.txt
文件来传递数据,作为一个不属于fastlane体系的类,不应该依赖从黑盒中拿到的逻辑来实现自己的目的——所以我们认为XCUITest和fastlane之间无法直接通讯 - 记得经常
fastlane snapshot update
,launch_arguments
在某个版本SnapshotHelper.swift
逻辑有问题,我排查了好久才发现是SnapshotHelper.swift
的问题,更新到新版本就可以了 - 现在维护fastlane的质量还有一些低级的错误。例如刚刚的一个升级提示
看说明里,是各种修复语法错误,词法错误。没想到,最后的说明里还是有个拼写错误ssigning
。真是不应该啊。
结语
对于自动化测试主题这个任务,本身用到fastlane的技术不是很多,也没有很高级的技巧。本文期望作为一个科普类的文章,展示fastlane作为日常工作流程里,解决如何自动化问题的一种尝试。
在各个项目里,用fastlane可以解决什么问题,取决于自己的想象。
文末附上resort_screenshot
action的源码,再次强调——并未开箱即用,需要和XCUITest的逻辑配合使用。
附录参考
- Fastlane入门:介绍篇 - 简书
- iOS中fastlane的使用
- ‘fastlane’ - Connect all iOS deployment tools into one streamlined workflow — Felix Krause
- 深入浅出 Fastlane 一看你就懂 · icyleaf
EOF
Author xiangheka
LastMod 2017-07-18