BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

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

| 作者 刘先宁 关注 2 他的粉丝 发布于 2013年9月18日. 估计阅读时间: 18 分钟 | 都知道硅谷人工智能做的好,你知道 硅谷的运维技术 也值得参考吗?QCon上海带你探索其中的奥义

测试框架

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

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT