东亚银行、岚图汽车带你解锁 AIGC 时代的数字化人才培养各赛道新模式! 了解详情
写点什么

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

  • 2013-09-17
  • 本文字数:4494 字

    阅读完需:约 15 分钟

测试框架

有了自动化构建和依赖管理之后,开发者可以很轻松的在命令行构建整个项目,但是,作为持续集成平台来说,最重要的还是测试,持续集成最大的好处在于能够尽早发现问题,降低解决问题的成本。而发现问题的手段主要就是测试。在 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-09-17 03:4010589

评论

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

Go语言,深入了解 RWMutex 实现原理

微客鸟窝

Go 语言 11月日更

【Flutter 专题】14 图解 ListView 不同样式 item 及 Widget 显隐性

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 11月日更

dart系列之:dart语言中的函数

程序那些事

flutter 后端 dart 程序那些事 11月日更

【死磕NIO】— 阻塞、非阻塞、同步、异步,傻傻分不清楚

chenssy

11月日更 死磕 Java 死磕 NIO

树莓派

IT蜗壳-Tango

11月日更

移动端自动化 AutoJS 快速入门指南

星安果

自动化 Autojs

算法入门-快速排序

ES_her0

11月日更

Flink 实践教程-入门(4):读取 MySQL 数据写入到 ES

腾讯云大数据

流计算 Oceanus

在IntelliJ IDEA中,开发一个摸鱼看书插件

小傅哥

Java 小傅哥 IDEA idea插件

Windoes下安装配置flutter环境

坚果

flutter windows 安装 11月日更

Android C++系列:通过 JNI 访问 Java 字段和方法调用

轻口味

android 11月日更

架构训练营毕业总结

SAKIN

爬虫120例之第17例,用Python面向对象的思路,采集各种精彩句子

梦想橡皮擦

11月日更

08 K8S之资源对象介绍

穿过生命散发芬芳

k8s 11月日更

死锁是如何工作的

卢卡多多

死锁 11月日更

模块9 毕设

SAKIN

Flink 实践教程-入门(5):写入 ClickHouse

腾讯云大数据

流计算 Oceanus

科技热点周刊|马斯克卖掉特斯拉 10% 股票;Facebook 停用面部识别系统;微软拥抱 Metaverse;雅虎退出中国

青云技术社区

云计算 facebook

在线2-36进制转文本工具

入门小站

工具

[ CloudWeGo 微服务实践 - 07 ] 阶段总结

baiyutang

golang 微服务 11月日更

构筑“数据连接器”,腾讯云大数据推出“开源开放”战略

腾讯云大数据

大数据

【LeetCode】键盘行Java题解

Albert

算法 LeetCode 11月日更

GitHub标星139K的:“嵌入式Linux系统开发教程”

Java Linux 编程 程序员

远程代码执行漏洞分析

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

linux几个没用但是有趣的命令

入门小站

Linux

Prometheus HTTP API 查询(二) 表达式查询

耳东@Erdong

Prometheus PromQL HTTP API 11月日更

正向代理和反向代理

liuzhen007

11月日更

aardio 开发桌面应用,这几点必须要掌握!

星安果

Python aardio

设计模式【3.3】-- CGLIB动态代理源码解读

秦怀杂货店

Java 设计模式

如何解决 fs.renameSync() 跨区移动文件的问题

liuzhen007

11月日更

《Kubernetes in action 读书笔记》:容器技术的发展

后台技术汇

Kubernetes 11月日更

构建iOS持续集成平台(二)——测试框架_DevOps & 平台工程_刘先宁_InfoQ精选文章