GMTC 全球大前端技术大会(北京站)门票 9 折特惠中,点击立减 ¥480 了解详情
写点什么

构建 iOS 持续集成平台(二)——测试框架

2013 年 9 月 17 日

测试框架

有了自动化构建和依赖管理之后,开发者可以很轻松的在命令行构建整个项目,但是,作为持续集成平台来说,最重要的还是测试,持续集成最大的好处在于能够尽早发现问题,降低解决问题的成本。而发现问题的手段主要就是测试。在 Martin Fowler 的 Test Pyramid【10】一文中论述了测试金子塔的概念,测试金字塔的概念来自 Mike Cohn ,在他的书 Succeeding With Agile 中有详细描述:测试金字塔最底层是单元测试,然后是业务逻辑测试,如果更细化一点的话,可以分为把完整的测试策略分为如下的层级:

作为持续集成平台,能自动化的测试层级越多,平台就能产生越大的价值。

Unit Test

目前,在 iOS 领域, 最流行的 Unit 测试框架有 2 个:OCUnit【11】和 GHunit【12】,这两个框架各有其优缺点:

优点

缺点

OCUnit

与 Xcode 无缝集成, 快捷键,Scheme 配置都非常方便

1. 只能一次运行整个测试,不能灵活的运行某个测试集 ; 2. 测试结果输出的可读性不好,不容易找到失败的测试

GHUnit

1. 自带 GUI,测试结果清晰可见;2. 可以灵活的运行指定的测试;3. 开源项目

1. 需开发者安装,配置略显复杂;2. 对命令行运行测试的支持不是很好,

OCUnit 的运行结果会通过弹窗直接告诉开发者,运行的细节信息则会打印在 Xcode 的输出窗口中:

GHUnit 的运行结果则全部显示在自己的应用界面中,开发者可以在应用中查看所有的信息,以及做运行测试等各种各样的操作。

关于如何使用 OCUnit 和 GHUnit, InfoQ 上有高嘉峻的文章《iOS 开发中的单元测试》( http://www.infoq.com/cn/articles/ios-unit-test-1)有详细的介绍,我就不再这儿重复叙述了。

如果单从单元测试框架来看,个人更喜欢 GHUnit 测试结果的可读性和运行测试的灵活性,但是,随着 Facebook 的 xctool 的发布,OCUnit 华丽丽的逆袭了,因为 xctool 帮助 OCUnit 把运行测试的灵活性和测试结果的可读性这两块短板给补齐了,再加上其和 Xcode 的集成优势以及通过命令行运行的便捷性,让其成为持续集成平台的 Unit 测试框架的首选。

在 Java 程序员的心中,Junit 和 Hamcrest 永远是一体的,Hamcrest 为 junit 提供了非常丰富的断言机制,极大的增强了测试的可读性。越来越活跃的 iOS 开发社区,当然不会让 Object-C 的世界缺失这样一个优秀的框架,于是 OCHamcrest【13】诞生了。

在测试项目中使用 OCHamcrest 非常简单,尤其是使用了 cocoapods 管理依赖的项目。只需要在 Podfile 文件中加上:

复制代码
target :<TestTargetName> do
...
pod 'OCHamcrest'
end

然后,运行“pod install”命令安装 Hamcrest 到测试 Target,安装好之后,为了在测试类中使用 OCHamcrest 的断言。还需要在测试类的头文件中加入如下代码:

复制代码
#define HC_SHORTHAND
#import<OCHamcrest/OCHamcrest.h>

开发者可以把这段代码加入-prefix.pch 中,这样所有的测试类就都可以使用 OCHamcrest 的断言了。在前面提到的高嘉峻的文章中的第二部分更加详细的讲解了 OCHamcrest 的断言,以及其和另一个断言框架 Expecta 的对比,感兴趣的同学可以跳过去看看( http://www.infoq.com/cn/articles/Matching-Engine-Enliven-Assertion-2?utm_source=infoq&utm_medium=related_content_link&utm_campaign=relatedContent_articles_clk )。

Component Test & Integration Test

在开发手机应用时,总难免会和其他的系统集成,尤其当开发的应用是某个系统的手机客户端时,这样就涉及到很多第三方 API 的集成点需要测试,在成熟的 Java 世界中,诞生了 EasyMock,Mockito,moco 等针对这种集成点的测试工具。同样的,活跃的社区力量正一步一步的在让 Object-C 世界成熟,OCMock【14】诞生。

OCMock

有了 cocoaPods,新加框架变得非常容易,基本上就是“哪里没有加哪里”的节奏,添加 OCMock 框架,只需要在 Podfile 文件中加上:

复制代码
target :<TestTargetName> do
...
pod 'OCMock', '~> 2.0.1'
end

然后,运行“pod install”命令安装 OCMock 到测试 Target,同样的,需要把 OCmock 的头文件添加-prefix.pch 文件中

复制代码
#import<OCMock/OCMock.h>

下面是一个简单的使用 OCMock 的例子,更多的用法请参考 OCMock 的官网: http://ocmock.org/features/:

复制代码
- (void)testSimpeMockPass{
idmockObject = [OCMockObjectmockForClass:NSString.class];
[[[mockObject stub] andReturn:@"test"] lowercaseString];
NSString * returnValue = [mockObjectlowercaseString];
assertThat(returnValue, equalTo(@"test"));
}

moco

moco【15】以其对系统集成点测试的贡献荣获了 2013 年的“Duke’s Choice Award”奖,虽然其以 Java 写成,主要的生态系统也是围绕 Java 打造,但是,其 Standalone 模式可以非常方便的构造一个开发者期望的服务器,这对于 Mobile 领域的集成点测试来说,本就是一个非常好的 Mock 服务器的工具。Moco 有如下的特点:

  • 易于配置,使用:一个 Json 配置文件,然后“java -jar moco-runner–standalone.jar -p 8080 ***.json”就可以启动一个 Mock 服务器。该服务器的所有行为都在配置文件里。如果你想添加,修改服务器行为,只需要修改一下配置文件,然后重新启动该服务器就行了。
  • 配置文件可读性好,使用 Json 格式的配置文件,对绝大多数开发者来说都可以很容易理解。
  • 支持模拟客户端需要的所有 http 操作,moco 实现了针对请求 Content、URI、Query Parameter、Http Method、Header、Xpath 的模拟。对响应的格式支持有 Content、Status Code、Header、URL、甚至支持 Sequence 请求,即根据对同一请求的调用次数返回不同的结果。
  • 完全开源,代码不多也比较易懂,如果没有覆盖到我们的场景,完全可以在该项目基础上实现一个自己的 Mock 服务器 。

熊节在 infoQ 上发表的《企业系统集成点测试策略》【16】一文中,详细的论述了在企业系统中,moco 对测试系统集成点的 帮助。这些论点在 Mobile 开发领域同样适用,因此合理的使用 moco 可以帮助 iOS 开发者更加容易的构建一个稳固的持续集成平台。

System Test

对于 iOS 的系统(UI)测试来说,比较知名的工具有 UIAutomation【17】和 FonMonkey【18】。

UIAutomation

UIAutomation 是随着 iOS SDK 4.0 引入,帮助开发者在真实设备和模拟器上执行自动化的 UI 测试。其本质上是一个 Javascript 的类库,通过 界面上的标签和值的访问性来获得 UI 元素,完成相应的交互操作,从而达到测试的目的,类似于 Web 世界的 Selenium。

通过上面的描述,可以得知,使用 UIAutomation 做测试时,开发者必须掌握两件事:

  • 如何找到界面上的一个 UI 元素
  • 如何指定针对一个 UI 元素的操作

在 UIAutomation 中,界面就是由一堆 UI 元素构建的层级结构,所有 UI 元素都继承对象 UIAElement ,该对象提供了每个 UI 元素必须具备的一些属性:

  • name
  • value
  • elements
  • parent

而整个界面的层级结构如下:

复制代码
Target(设备级别的 UI,用于支持晃动,屏幕方向变动等操作)
Application(设备上的应用,比方说 Status Bar,keyboard 等)
Main window(应用的界面,比方说导航条)
View(界面下的 View,比方说 UITableView)
Element(View 下的一个元素)
Child element(元素下的一个子元素)

下面是一个访问到 Child element 的例子:

复制代码
UIATarget.localTarget().HamcrestDemo().tableViews()[0].cells()[0].elements()

开发者还可以通过“UIATarget.localTarget().logElementTree()”在控制台打印出该 target 下所有的的 elements。

找到 UI 元素之后,开发者可以基于该 UI 元素做期望的操作,UIAutomation 作为原生的 UI 测试框架,基本上支持 iOS 上的所有 UI 元素和操作,比方说:

  • 点击按钮,例: ***.buttons[“add”].tap()
  • 输入文本, 例:***.textfields[0].setValue(“new”)
  • 滚动屏幕,例:***.scrollToElementWithPredicate(“name begin with ’test’”)
  • ……

关于使用 UIAutomation 做 UI 测试,推荐大家一定要看一下 2010 的 WWDC 的 Session 306: Automating User Interface Testing with Instruments 【19】。 另外,这儿还有一篇很好的博客,详细的讲解了如何使用 UIAutomation 做 UI 自动化测试: http://blog.manbolo.com/2012/04/08/ios-automated-tests-with-uiautomation

Apple 通过 Instruments 为 UIAutomation 测试用例的命令行运行提供了支持,这样就为 UIAutomation 和 CI 服务器的集成提供了便利。开发者可以通过如下的步骤在命令行中运行 UIAutomation 测试脚本

  1. 指定目标设备,构建被测应用,该应用会被安装到指定的 DSTROOT 目录下
复制代码
xcodebuild
-project "/Users/twer/Documents/xcodeworkspace/AudioDemo/AudioDemo.xcodeproj"
-schemeAudioDemo
-sdk iphonesimulator6.1
-configuration Release SYMROOT="/Users/twer/Documents/xcodeworkspace/
AudioDemo/build" DSTROOT="/Users/twer/Documents/xcodeworkspace/AudioDemo/
build" TARGETED_DEVICE_FAMILY="1"
install
  1. 启动 Instruments,基于第一步生成的应用运行 UIAutomation 测试
复制代码
instruments
-t "/Applications/Xcode.app/Contents/Applications/Instruments.app/
Contents/PlugIns/AutomationInstrument.bundle/Contents/Resources/
Automation.tracetemplate" "/Users/twer/Documents/xcodeworkspace/AudioDemo
/build/Applications/TestExample.app"
-e UIASCRIPT <absolute_path_to_the_test_file>

为了更好的展示测试效果以及与 CI 服务器集成,活跃的社区开发者们还尝试把 UIAutomation 和 Jasmine 集成: https://github.com/shaune/jasmine-ios-acceptance-tests

UIAutomation 因其原生支持,并且通过和 Instruments 的绝佳配合,开发者可以非常方便的使用录制操作自动生成测试脚本,赢得了很多开发者的支持,但是因苹果公司的基因,其系统非常封闭,导致开发者难以扩展,于是活跃的社区开发者们开始制造自己的轮子,Fone Monkey 就是其中的一个优秀成果。

Fone Monkey

Fone Monkey 是由 Gorilla Logic 公司创建并维护的一个 iOS 自动化测试工具,其功能和 UIAutomation 差不多,但是由于其开源特性,极大的解放了活跃开发者的生产力,开发者可以很容易的根据自身需要扩展其功能。

Fone Monkey 的安装虽然简单,但是比 UIAutomation 的原生支持来说,也算是一大劣势了,具体的安装过程可以参考: http://www.gorillalogic.com/fonemonkey-ios/fonemonkey-setup-guide/add-fonemonkey-your-xcode-project

Fone Monkey 的使用方式主要就是录制 / 回放,也可以把录制好的测试用例保存为脚本以其他方式运行。安装好 Fone Monkey 启动测试以后,应用界面会有点变化:

开发者通过点击 Record 按钮录制操作,点击 Play 按钮播放之前录制的操作,点击 More 按钮可以添加一些针对元素的验证, 这样就形成了一个测试用例。

在 Fone Monkey 中录制的测试用例可以保存为 3 种格式,以支持多种运行方式:

  • scriptName.fm:用于支持在 Fone Monkey 的窗口中运行测试
  • scriptName.m:用于和 Xcode 的 OCUnit test 集成,可以以 OCUnit 的测试用例的形式运行 UI 测试,这就让 UI 具备了命令行运行和与 CI 集成的能力。
  • scriptName.js:UIAutomation 的格式,用于支持在 Instruments 中,以 UIAutomation 的形式运行测试。
2013 年 9 月 17 日 03:4010100

评论

发布
暂无评论
发现更多内容

如何设计一个亿级消息量的IM系统

Chank

Java Architecture Architect IM Instant Messaging

QQ音乐PB级ClickHouse实时数据平台架构演进之路

小小的一朵云

大数据

NameNode和SecondaryNameNode工作机制

奈学教育

NameNode

第八周作业

andy

极客大学

当远程工作成为未来的工作方式......

Atlassian

Atlassian Jira

一个小实验,来

池建强

算法 薪资

真香!Linux 原来是这么管理内存的

cxuan

Linux 操作系统

实战:docker搭建FastDFS文件系统并集成SpringBoot

生命在于折腾

springboot

蚂蚁上市:P7可获1200万元期权,酸酸酸酸酸...

程序员生活志

互联网热点 蚂蚁金服

第八周总结

andy

极客大学

保障服务稳定之服务限流

X先生

架构设计 服务设计 后端开发 限流算法

企业为何需要建立统一的复用型软件平台?

力软.net/java开发平台

Java 企业信息化 开发工具 框架 平台应用服务

Django框架,Flask框架和Tornado框架各有什么优缺点

古月木易

django flask tornado

架构训练营第八周作业

张锐

第八周作业

田振宇

如何成为一个成功的首席数据官

尹千觞

LeetCode题解:142. 环形链表 II,JavaScript,快慢指针,详细注释

Lee Chen

LeetCode 前端进阶训练营

乘商用之风,破后疫情之浪:丁耘分享华为如何持续护航5G新价值

脑极体

你好,工作!

小天同学

工作 心态 自我思考

腾讯“神盾-联邦计算”平台带你翻越数据合作的重重大山

小小的一朵云

大数据

顺势昌,逆势亡:人啊,得学会做信天翁,而不是鹧鸪鸟

非著名程序员

创业 程序员 管理 提升认知

一周信创舆情观察(7.20~7.26)

统小信uos

秒杀全网!研发、运营必备实用工具网站

程序员生活志

工具类网站

week08 总结

Z冰红茶

央行数字货币或将成为经济“内循环”的未来加速器

CECBC区块链专委会

数字经济 全球经济下行 降息 惠普金融深化

什么样的信任才值得拥有?谈一谈极客邦的5K1S文档

霍太稳@极客邦科技

NameNode和SecondaryNameNode工作机制

古月木易

NameNode econdaryNameNode

Flink 1.11 SQL 使用攻略

Apache Flink

flink

国家版权局发布《关于规范摄影作品版权秩序的通知》

CECBC区块链专委会

电子存证 作品版权 侵权盗版 剑网2019

Django框架,Flask框架和Tornado框架各有什么优缺点

奈学教育

django flask tornado

第八周作业

赵龙

DIY 的 Kubernetes 集群的稳定性保障实践

DIY 的 Kubernetes 集群的稳定性保障实践

构建iOS持续集成平台(二)——测试框架-InfoQ