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

来源:互联网 发布:巨灵数据 编辑:程序博客网 时间:2024/05/01 21:56

【原文地址:http://www.infoq.com/cn/articles/build-ios-continuous-integration-platform-part2#0-tsina-1-33218-397232819ff9a47a7b7e80a40613cfe1】

测试框架

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

开发者可以把这段代码加入<TestTargetName>-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的头文件添加<TestTargetName>-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
  2. 启动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的形式运行测试。

0 0
原创粉丝点击