工业时代流水线的发明将生产任务的效率大大提升。同样,在软件开发过程中流水线的建立也能帮助我们更好的产出、提升效率。
流水线的建立准则应该符合每个团队自己的需求,比如你的团队管理策略、分支管理策略,接下来以我们最近的给客户做的案例进行总结说明:
我们首先需要制定我们流水线的策略,需要哪几个任务,进行任务的拆分:
iOS:
| 主分支每次提交进行构建触发单元测试
|
|--功能测试构建分发
| |
| |--各个执行功能测试的节点并行执行功能测试
| |
| |--聚合各个节点的功能测试结果输入报告
|
|--adhoc分发通知测试人员
|
|--enterprise分发通知测试人员
|
|--appstore提审核
|
Android:
| 主分支每次提交进行构建触发单元测试
|
|--功能测试构建分发
| |
| |--各个执行功能测试的节点并行执行功能测试
| |
| |--聚合各个节点的功能测试结果输入报告
|
|--打release包通知测试人员测试
|
|--打各种渠道包
其中的功能测试板块由客户的测试团队负责日常的监控以及维护,不干扰开发团队日常的开发。不是整个任务成功的必要条件,而在我之前的开发项目中,功能测试是由开发人员与测试人员一起结对书写,因此会把它作为发测试包的前置步骤,这点根据每个团队的实际情况考量。
工具集:
工欲善其事,必先利其器。要想自动化整个过程,离不开工具的支持。
通用:
Jenkins:用的最广持续集成工具,但是本身并不提供流水线功能,需要插件支持
Gem:ruby包管理工具,比如我们执行功能测试Appium、Calabash等都是通过gem来安装的。
rbenv:管理ruby,用它来统一ruby环境。
bundle:用来管理gem包,比如gem包的版本等。
rake:用ruby时间的类似于make的构建工具,我们的任务脚本使用rake来写的,选自己顺手的就好了。
cucumber:基于BDD的自动化测试框架
iOS:
shenzhen:对,深圳,作者写了一堆用城市命名的工具。这个是用来构建ipa以及分发的,不过我只用了它的分发功能,还是直接用的xcodebuild构建。
calabash:iOS端用来进行自动化功能测试的工具,基于cucumber。
Android:
Appium:类似于calabash的自动化测试框架。之所以没有在安卓上用calabash,是因为项目中用了蚂蚁金融的一个SDK,其对测试不太友好,不支持像calabash这样使用Instrumentation的框架。
关键设计:
持续对主分支进行构建:
我们需要保证开发团队的每一次代码提交都是能工作,能通过测试的,相比传统开发过程中在最后关头进行测试,大大降低了风险。
如下图,需要在任务配置中写上执行策略,比如你想每两分钟去检测一次你的代码库有没有代码变化,如果有变化,Jenkins会立刻开始执行构建。
每两分钟检测一次代码库拉取下了代码之后之后需要构建并执行单元测试,iOS使用xcodebuild
,安卓使用gradle
。
如何串连流水线:
当构建没问题之后,我们需要在构建后步骤中将下游的任务串连起来,这里有两种方式,一种是自动触发下游任务,一种是手动触发。比如我们的发包步骤就是运营人员手工操作,执行功能测试到合并报告就是自动进行的。
自动触发:
这里需要选择Trigger parameterized build on other projects,指明下游任务的名字。根据需要制定触发条件,以及传递的参数等。
手动触发:
这里需要选择Build other projects(manual steps),我们需要指定下游任务的名称。传递git commit过去是为了保证下游任务产品代码与当前保值一致,除此之外还会传递一些预定义的参数到下游。
手工触发截图并行执行功能测试
需求是需要在多台节点上并行地执行功能测试,比如我要在天津的一台机器用三星 note跑测试,我要在成都的一台机器用 另外一台手机跑。
为了解决这个需求,我需要加入一个多配置的任务,然后在Configuration Matrix中进行配置,如图,把能够执行这个任务的多个节点给选上。
Configuration Matrix如何合并多个cucumber报告
这里分两步,首先需要把每个节点的测试结果收集起来,然后传递到下游去,通过传递归档文件就可以完成这一步。比如我任务完成了之后会生成一个build
目录,我需要把多台节点的这个目录传递过去。这里需要注意的点在于,每个节点生成的结果会加上自己的机器前缀。比如会像这样mac_chengdu/build,我们需要使用通配符 ****/build/**表示。
接下来是合并,因为cucumber生成的报告结果可以是json的,这一步就是在解析json的结果,我fork了cucumber-html-reporter对进行修改,做成了一个node的命令行工具,可以参考这里。
关于自动化测试
iOS和安卓的开发中本身就提供单元测试的支持,比如iOS提供XCTest,安卓有JUnit,根据需要进行调整,比如iOS上我使用的Kiwi。
单元测试比较简单,主要看团队对这东西的认识。主要聊一下功能测试这块遇到的坑。
先说iOS,iOS上采用的calabash,一个是项目组之前也在用,二个是我在调研了appium之后,发现appium最新版本才开始支持XCUITest做功能测试,存在一些bug且功能不够完善,因此果断上calabash。
在安卓遇到的坑相对来说多一点,首先calabash在安卓上底层是用的Instrumentation
,调研过calabash的源码发现如果要让它支持UIAutomator
的话,基本上等于重新造一个轮子了,因此如果你的产品不支持Instrumentation
的话需要注意了。
那么appium呢,appium 配合cucumber在安卓上看起来不错的。我开开心心地用了起来,结果看报告发现这家伙在失败的时候不会主动截图,看样子得自己去实现了,好在cucumber提供了一些hook的方法,比如可以在每个执行步骤之后做点什么。
我一开始是在cucumber的AfterStep
中加入了截图的方法,可是发现并没有什么用,后来查了一会儿发现已经有人给cucumber提过这个[issue](bundle exec cucumber #{feature}--tags ~@pending --format json --out #{BUILD_DIR}/functionals.json --format NewHtml --out #{BUILD_DIR}/functionals.html),原来cucumber设计上就是这样考虑的,失败了的步骤不允许hook。
既然cucumber这一层做不了,那只能在appium这一层做手脚了。经过观察,失败场景大多是找不到元素,因此我需要解决的主要问题是在找不到元素的时候进行截图。我在appium-lib中找到了driver.rb
,看了下它提供了几个查找元素的方法,底层是用的selenium-webdriver
进行操作,那么我的需求应该在driver这层就能够解决,我只需要在这几个方法执行失败后加上截图保存的方法就好了。Ruby我不熟悉,我查了下有几种方式可以解决,你可以新建一个子类重写这几个方法,你可以利用ruby的动态性把这几个方法给动态的替换了。我这里采用的是第二种方式,代码如下:
module DriverExtension
def store_callback_after_fail(&block)
@execute = block
end
def take_screenshot_when_fail
@@screenshot_count ||= 0
$filename = "./build/" + "Screenshot-" + "#{@@screenshot_count}" + ".png"
File.delete($filename) if File.exist?($filename)
screenshot($filename)
@execute.call($filename)
end
def find_element(*args)
begin
result = super
result
rescue Exception => e
take_screenshot_when_fail
raise
end
end
...
...
end
module Appium
class Driver
prepend DriverExtension
end
end
采用流水线之后可以大幅度的减少人力成本,比如我们的客户之前还有安排同事专门负责构建打包上传等任务,代码出了问题也很难追溯到底在哪一步出了错。现在整个流程自动化了后,开发人员只需要更加专注于手中的开发任务,测试人员想什么时候测就什么时候测,要做的只需要点个按钮就好,是不是很赞!
网友评论