分享

从零开始使用Xcode自动化测试

 没原创_去搜索 2015-09-10

你用哪种工具进行iOS app自动化功能测试?


在iOS项目开发上,我一直在寻找合适的自动化功能测试库,感觉现在的自动化测试有点类似于10年前的自动化web测试。虽然有不少不一样的支持iOS自动化功能测试的工具,但我们需要通过实践来检验哪个才是最好的。
 
我推崇使用和代码库一样的语言来写功能测试,就iOS和Objective C来说,我觉得使用更加轻量级的语言(比如Ruby)会有优势。我还会经常为Android写测试案例,所以能够用与iOS app测试相同的工具更具优势。以下列出了几种iOS app自动化功能测试工具:FrankKIFSubliminalZucchiniCalabashAppium以及ios-driver。 (有些框架使用了苹果未公开的API,这一点要注意)
 
 

 原文:The current state of iOS automated functional testing




==============================
http://www./archives/2245


如何使用UIAutomation进行iOS 自动化测试(Part I)


写在前面

研究iOS的自动化测试也有些日子了,刚开始的时候,一直苦于找不到什么好的资料,只能从Apple的官网查阅相关的API文档,只可惜,Apple对开发者来说实在是不怎么友好,文档写得相当的粗略,对于初学者来说有一定的难度。

本来是打算自己动手写一篇关于iOS的UI自动化测试的入门级别的介绍性文档的,但想起来后面在具体解决一些问题的时候,收藏一篇很好的Blog,很全面地介绍了如何使用UIAutomation的JavaScript Libraries做iOS程序的自动化测试。如果作者早点看到这篇文章,应该要少走一些弯路,这里没有创意性的它他翻译成中文,希望对你们有一些帮助。

原文地址:http://blog./2012/04/08/ios-automated-tests-with-uiautomation

翻译正文:

快速入门

自动化测试代码可以“在你的睡着的时候”很好地帮你测试你的应用程序。它可以让你能够快速地跟踪你程序中的回归和性能方面的问题,这样你就不用担心你新增的功能会影响到你之前已经完成开发的程序了。

随着iOS4.0的发布,苹果公司同时发布了一个名为UIAutomation的测试框架,它可以用来在真实设备和iPhone模拟器上执行自动化测试。但官方关于UIAutomation的文档相当的有限,在网络上也没有太多的资源可以查找的。本文将向你展示你如何将UIAutomation整合到你的工作流程当中去。

作为基础知识的准备,你可以先看一下苹果公司关于UIAutomation的文档,另外还有一篇快速入门的介绍苹果Instruments的文档也值得看看,当然,如果你有一个免费的Apple开发者账号的话,你可以看一下WWDC 2010 - Session 306 – 使用Instruments进行用户界面自动化测试的幻灯片或者视频。

除此之外,包括在Xcode中的OCUnit测试框架也可以用来为你的应用程序编写单元测试。

1. 第一个UIAutomation测试脚本

  • 使用iOS 模拟器

  • 使用iOS设备

2. 处理UIAElement和元素可访问性(Accessibility)

  • UIAElement层次结构

  • 模拟用户操作

3. 经验分享(让你的生活变得更简单)

  • 类库Tune-up介绍

  • 导入外部脚本

  • 使用强大的命令行

  • 使用录制交互功能

  • 当遇到问题时,加上“UIATarget.delay(1);”

4. 高级交互

  • 处理非预期和预期的提示框(alerts)

  • 多任务

  • 屏幕方向

5. 总结

  • 有用的链接

  • 一个视频

1. 你的第一个UIAutomation测试脚本

UIAutomation的功能测试代码是用Javascript编写的。UIAutomation和Accessibility有着直接的关系,你将用到通过标签和值的访问性来获得UI元素,同时完成相应的交互操作。

下面让我们来编写我们的第一段测试代码。

使用iOS模拟器

1. 下载示例应用程序TestAutomation.xcodeproj,并打开它。这个项目是一个很简单的包含2个tab的tabbar应用程序。

2. 确保选中如下图所示的“TestAutomation > iPhone 5.0 Simulator”模式(或许你已经切换成5.1了,因此它可能是iPhone5.1模拟器)。

clip_image001[4]

3. 启动Instruments(Product > Profile),或者通过?I。

4. 选择左边的iOS Simulator,然后再选择Automation模板,然后点击“Profile”。

clip_image002[4]

5. Instruments就已经启动好后,然后直接开始录制了。这里先停止录制,(红包按钮或者?R)。

clip_image004[4]

6. 在左边的Scripts窗口,点击“Add > Create”创建新的脚本。

clip_image005[4]

7. 在脚本编辑器里,输入下面的代码

var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
target.logElementTree();

clip_image007[4]

8. 重新运行这段脚本?R(不需要保存)。脚本跑起来后,你可以在日志打完后停止它。

clip_image009[4]

赞一个!我们就这样完成了我们的第一个UIAutomation测试用例。

使用iOS设备

你除了将你的测试用例运行模拟器上,也可以将它运行在一个真实的设备上。不过,自动化测试用例只能运行在支持多任务的:iPhone 3GS,iPad,iOS > 4.0等设备上。遗憾的是不管iPhone 3G的系统版本是什么,都不支持。

下面是如何操作:

1. 通过USB接口连接上你的iPhone。

2. 选择 “TestAutomation > iOS Device”模式。

3. 确保Developper profile设置成Release模式(而不是Ad-Hoc Distribution profile)。默认情况下,profiling是设置成Release模式的(因为没有必要将profile设置成Debug模式)。

clip_image010[4]

4. 启动测试 (?I)

5. 后面的步骤请参考前面模拟器部分。

2. 处理UIAElement和元素可访问性(Accessibility)

UIAElement层次结构

Accessibility和UIAutomation有密切的联系:如果一个控件的Accessibility是可以被访问的,你就可以设置和读取它的值,作相关的操作,而当一个控件的Accessibility不可见时,你就没有办法通过automation访问它。

你可以通过Interface Builder,或者通过在程序里设置isAccessibilityElement属性的方式来设置一个控件的Accessibility或者可被自动化。当你设置container view(即:一个视图包含其它的UIKit元素)的accessibility时,你必须注意。你设置了整个View的accessibility将会“隐藏”它的子视图的accessibility,例如:在示例项目中,你不能将outlet视图设置成可访问的,否则它所有的子控件将都不可以访问了。在任何时候,logElementTree都是你忠实的朋友:它将当前界面的所有可被访问的元素都打印在日志里。

每一个可以被访问的UIKit控件都可以用一个Javascript对象来描述,它就是一个UIAElement。UIAElement有几个属性:name, value, elements, parent。你的主窗口包含很多的控件,它们是以UIKit层次的方式定义的,这些UIKit层次结构对应的是UIAElement的层次树。例如:前面的测试代码中,通过调用logElementTree,我们可以得到如下面所示的树结构:

+- UIATarget: name:iPhone Simulator rect:{{0,0},{320,480}}

| +- UIAApplication: name:TestAutomation rect:{{0,20},{320,460}}

| | +- UIAWindow: rect:{{0,0},{320,480}}

| | | +- UIAStaticText: name:First View value:First View rect:{{54,52},{212,43}}

| | | +- UIATextField: name:User Text value:Tap Some Text Here ! rect:{{20,179},{280,31}}

| | | +- UIAStaticText: name:The text is: value:The text is: rect:{{20,231},{112,21}}

| | | +- UIAStaticText: value: rect:{{145,231},{155,21}}

| | | +- UIATabBar: rect:{{0,431},{320,49}}

| | | | +- UIAImage: rect:{{0,431},{320,49}}

| | | | +- UIAButton: name:First value:1 rect:{{2,432},{156,48}}

| | | | +- UIAButton: name:Second rect:{{162,432},{156,48}}

clip_image001[6]

你可以通过下面的代码来访问文本框:

var textField = 
UIATarget.localTarget().frontMostApp().mainWindow().textFields()[0];

你可以选择通过从0开始的索引或者这个元素的名称来访问这个元素,例如:你也可以通过下面的代码来访问文本控件。

var textField = 
UIATarget.localTarget().frontMostApp().mainWindow().textFields()["User Text"];

后一种方式更加清晰明了,应该多使用。你可以通过Interface Builder设置UIAElement的name属性,

clip_image002[6]

或者通过编写代码的方式:

myTextField.accessibilityEnabled = YES;
myTextField.accessibilityLabel = @"User Text";

你现在可以看到,通过accessibility属性可以被UIAutomation用来找到不同的控件。这非常的清晰,因为,第一,你只要学习一个测试框架;第二,通过编写自动化测试代码,你同时还可以保证你的程序是可以被访问的。因此,每一个UIAElement对象的子控件可以通过下面的方法进行访问:

buttons(), images(), scrollViews(),textFields(), webViews(), segmentedControls(), sliders(), staticTexts(), switches(), tabBar(),tableViews(), textViews(), toolbar(), toolbars() 等等……

你可以通过如下代码在tabbar上访问第一个tab:

var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons()["First"];

UIAElement结构层次非常的重要,你以后会常常用到它。而且你还要记住,你可以在随时通过调用UIAAplication的logElementTree来获得它的结构。

UIATarget.localTarget().frontMostApp().logElementTree();

在模拟器上,你还可以激活Accessibility 的检测器。启动模拟器,找到“Settings > General > Accessibility > Accessibility Inspector”,然后将它设为“打开”状态。

clip_image003

这个彩色的小框框就是Accessibility 检测器了。当它收起来的时候,Accessibility就被关闭了,当它展开的时候,Accessibility就是打开的。你只要点击上面的箭头按钮就可以激活或者屏蔽Accessibility。现在,打开我们的示例程序,激活检测器。

 clip_image004

然后,点击文本框,检查UIAElement的name和value属性(其实就是accessibilityLabel和accessibilityValue对应的NSObject类型的值)。这个检测器可以帮助你调试和编写你的测试代码。

模拟用户操作

让我们更进一步,模拟一些用户的交互操作。你可以简单地调用按钮的tap()来作一个点击操作:

var tabBar = UIATarget.localTarget().frontMostApp().tabBar();
var tabButton = tabBar.buttons()["First"];   

// Tap the tab bar !
tabButton.tap();

你还可以调用UIAButtons的doubleTap(), twoFingerTap()。如果你不想操作具体的某个元素,你也可以直接根据屏幕上指定的坐标点进行操作,你可以这么用:

  • 点击:

UIATarget.localTarget().tap({x:100, y:200});
UIATarget.localTarget().doubleTap({x:100, y:200});
UIATarget.localTarget().twoFingerTap({x:100, y:200});
  • 缩放:

UIATarget.localTarget().pinchOpenFromToForDuration({x:20, y:200},{x:300, y:200},2);
UIATarget.localTarget().pinchCloseFromToForDuration({x:20, y:200}, {x:300, y:200},2);   
  • 拖拽与划动:

UIATarget.localTarget().dragFromToForDuration({x:160, y:200},{x:160,y:400},1);
UIATarget.localTarget().flickFromTo({x:160, y:200},{x:160, y:400});

注意,当你指定操作的时间间隔的时候,它是有特定的范围的,即:拖拽操作的时间间隔必须大于或者等于0.5秒,小于60秒。

现在,让我们来练习一下:

  1. 停止Instruments (?R)

  2. 在Scripts窗口里, 移除当前的脚本

  3. 点击“Add > Import”然后选择TestAutomation/TestUI/Test-1.js(将下面的代码保存到这个路径)

  4. 点击录制按钮 (?R) 然后看看将会发生什么…

下面是Test-1.js代码:

var testName = "Test 1";
var target = UIATarget.localTarget();
var app = target.frontMostApp();
var window = app.mainWindow();
UIALogger.logStart( testName );
app.logElementTree();
//-- select the elements
UIALogger.logMessage( "Select the first tab" );
var tabBar = app.tabBar();
var selectedTabName = tabBar.selectedButton().name();
if (selectedTabName != "First") {
	tabBar.buttons()["First"].tap();
}
//-- tap on the text fiels
UIALogger.logMessage( "Tap on the text field now" );
var recipeName = "Unusually Long Name for a Recipe";
window.textFields()[0].setValue(recipeName);
target.delay( 2 );
//-- tap on the text fiels
UIALogger.logMessage( "Dismiss the keyboard" );
app.logElementTree();
app.keyboard().buttons()["return"].tap();
var textValue = window.staticTexts()["RecipeName"].value();
if (textValue === recipeName){
	UIALogger.logPass( testName ); 
}
else{
	UIALogger.logFail( testName ); 
}

这段脚本先启动待测程序,然后,如果第一个tab没有被选的话就切换到第一个tab,并将上面的文本框的值设成“Unusually Long Name for a Recipe”,接着收起虚拟键盘。这里有一些新的方法值得注意的:UIATarget的delay(Number timeInterval) 方法允许你在两个操作之间做一些等待,UIALogger的logMessage( String message) 方法用来将你想打印的信息输出到日志上去,UIALogger的logPass(String message)方法指明你的测试脚本已经成功的完成测试了。

你还知道了如何访问键盘上的按钮,然后作点击操作:

app.keyboard().buttons()["return"].tap();

由于时间有限且原文太长,先只能翻译到这里,我会尽快的将剩下的部分翻译补上。另外,时间仓促,如有翻译得不准确的地方,也敬请担待。谢谢。

本文由知平软件的Dawson Liu翻译,转载请注明出处。

知平软件致力于移动平台自动化测试技术的研究,我们希望通过向社区贡献知识和开源项目,来促进行业和自身的发展。

var isLogined = false; var cb_blogId = 123488; var cb_entryId = 2631949; var cb_blogApp = currentBlogApp; var cb_blogUserGuid = "4c20a564-9fd4-e111-aa3f-842b2b196315"; var cb_entryCreatedDate = '2012/8/10 15:47:00'; var enableGoogleAd = true; var googletag = googletag || {}; googletag.cmd = googletag.cmd || [];

原文地址:http://www.cnblogs.com/vowei/archive/2012/08/10/2631949.html
本文地址:蓝色梦想网:http://www./BBS/TechBSS/Article-3509.html
TAG标签:


==============================

翻译:子玉冰,JX,为爱西行,杰西,benna Review:蓝羽

Learn how to add automated testing into your iOS 6 apps!

Ray的注释:这是第十章也是在iOS 6 盛宴中iOS 6教程最后一章!这篇教程来自我们的新书iOS 6 教程。查理.富尔顿写了这章,他是我的朋友也是教程团队的一名新进成员。欢迎!

这是一篇iOS教程团队成员查理.富尔顿写的博客文章,他是一个全职的iOS开发人员,他喜欢打猎、钓鱼还有和他的家人聚会。

所有的开发人员都需要测试他们的软件,并且,许多聪明的人为此创建了测试套件。测试套件是一组测试用例,也被称为单元测试,针对小“单元”代码,通常是一个特殊的方法或者类。

单元测试允许你使用驱动测试开发实践,确保你的代码更少的错误!通过为每个bug创建一个单元测试,你可以确保bug不再出现。通过单元测试和预先调试,你能极大的减少你的应用在发环境出现异常的机会

但如你所知,我们经常急于完成 –或者我们偷懒所以每次你改变代码时单元测试能自动运行会更好。当你作为一个团队的一员在工作时,这是特别重要的。

所以,如果你能设置一个系统能自动构建、测试,然后提交你的应用程序到测试人员,你会感兴趣吗?如果会,那么继续阅读吧!

这个额外一章和下一章将带你为iOS应用建立一个自动化构建和测试的系统。你将得到一个示例项目,添加一些单元测试在里面,添加一个远程GitHub(github.com)存储库,然后用Jenkins(基于Java开发的一种持续集成工具)创建一个持续集成(CI)服务器,它将定期检查你的GitHub存储库的变化和自动构建、测试和提交应用程序到TestFlight上。

如果你是自动化测试初学者,你可能会想了解一些(或者全部)上面的术语,包括GitHub, Jenkins, TestFlight。在这个教程中我们将涉及到其中的每个细节,但是现在只细微介绍这些工具。

 GitHub-公共免费Git存储库,合作者管理,问题追踪,维基,下载,代码评审、图形,还有更多功能。

 Jenkins –持续集成服务器和调度程序,可以监测Git存储库的变化, 自动开始构建和测试,并通知你结果。

TestFlight通过无线的方式自动发送iOS应用程序给测试人员, 并且能进行崩溃日志分析

这个简短的讲解应该能让你在短时间内摆脱困境,让我介绍相当精彩的项目示例geektastic, 这将是你在这个教育历险中的交通工具——但可以在后面了解更多关于所有这些!

GuildBrowser介绍

在本教程中,您将创建一个自动化的构建和测试系统GuildBrowser 。GuildBrowser是一个简单的应用程序,允许您从受欢迎的游戏《魔兽世界》里浏览一个公会的成员们。您可以输入一个工会和一个域名看到UICollectionViewController上所有成员列表,正如你下图所示:

这个应用程序是由暴雪免费提供的魔兽世界 API驱动的。您将使用AFNetworking框架对WOW API 进行平稳的调用、获得JSON数据,这些数据包含工会和角色信息。

如果你从未有时间玩游戏,接下来最好是让应用程序帮助你游戏!

:对于更详细的魔兽世界API,看看暴雪的GitHub项目(https://github.com/Blizzard/api-wow-docs),官方的魔兽世界 API文档(http://blizzard.github.com/api-wow-docs/),魔兽世界 API 论坛(http://us./wow/en/forum/2626217/).

开始

如果你近来没有对你的代码用到过某种形式的版本控制,那么你绝对做的不对!可以说当下最受欢迎的系统是GitLinus Torvalds(是的,就是他创建的Linux)设计并发展Git使它成为了比它前任SVN更好的系统, 去管理Linux内核代码。git不仅是一个伟大的源代码控制系统,而且它还被直接集成进Xcode,这使得它非常方便地对IOS进行开发。

Git是一个分布式版本控制系统,这意味着每个Git工作目录是它自己的存储库,而不是依赖于一个中央系统。

然而,当你想给其他开发者分享本地资源库时,你要在“远程”设置上定义一个连接。远程存储库的项目版本通常设置在一个中央远程服务器上。它们可以通过一个Dropbox文件夹共享(虽然这不是特别推荐)。

在过去一些年一些服务已经出现了,使得更容易建立Git远程存储库,以及其他分布式版本控制系统。Github 已经成为这些服务中最好的和最受欢迎的,并有充分的理由。它提供免费公共的Git存储库,合作者管理、问题跟踪、维基、下载、代码评审、图表和更多…对不起,听起来像是一个广告,Github相当棒!

:关于更多Git详细的描述和如何使用它开展工作,请在raywenderlich.com查阅如何在IOS 6Xcode使用Git源代码控制教程。

在这篇教程中首先你将在GitHub上建立一个远程存储库。它将是你的远程“原始”存储库。它允许你在本地照常工作,并且当你准备与团队成员同步或发送一条新的构建给测试人员时,你将把所有你的本地修改提交到这个存储库。

:本教程假定你已经有了一个设置了SSH密钥访问的GitHub账户。如果你不会弄,请查阅本指南(https://help.github.com/articles/generating-ssh-keys), 这里告诉你通过生成 SSH 秘钥对来设置账号。 您还可以通过你的GitHub用户名/密码使用一个https URL,但这篇教程假设使用的是SSH密钥访问。

首先,通过选择Xcode/Preferences/Downloads标签确定你已经安装了命令行工具,并且确定你的屏幕看起来像下面这样(重要的是旁边的命令行工具是Installed):

本教程附带了一个初始工程项目,你可以点击这里下载。复制工程到硬盘任意你指定的地方,然后在Xcode中打开GuildBrowser工程。GuildBrowser通过Single View Application模版创建,并勾选了ARC,Unit testing, Storyboards, iPad-only,和local Git repository选项。编译运行之后,你应该能够看到来自默认工会的一些人物。

打开浏览器,前往github.com并登陆你的账号。如果没有账号,请创建一个新账号并登陆。然后点击右上角Create a New Repo按钮,如下图所示:

Repository nameDescription栏输入任意你喜欢的内容,Repository名字不需要和你Xcode工程名相同。然后点击Create repository按钮。

:不要勾选the Initialize this repository with a README选框。你只需要创建一个空存储库,然后将你的Xcode工程推送(push)到该存储库中。

点击copy to clipboard按钮或者?+C来复制存储库的SSH URL (不要忘记了先点击SSH按钮切换到SSH URL)。

现在打开Organizer (Cmd-shift-2),然后选择Repositories标签。

你应该在左下角看到GuildBrowser工程。点击Remotes文件夹,然后点击Add Remote按钮。

Remote Name一栏输入origin,然后粘贴你之前复制的GitHub URLLocation一栏:

wps_clip_image-26686[4]

点击Create,然后Organizer应该如下图所示:

wps_clip_image-22023[4]

尽管没有为原始地址输入密码,不过不要慌张。你会使用Git的SSH来进行访问,所以不需要密码。

你现在已经建立好了一个远程存储库!当然你也可以使用同样的步骤来为其他所有的Xcode工程进行设置。虽然远程存储库已经建立好,但是你仍然没有从本地Git存储库推送任何文件到远程Git存储库。我们接下来使用Xcode来完成这个任务。

回到你的工程,首先确定你已经提交了所有的本地修改。如果你有修改没有提交,那么Xcode将不允许你推送的远程存储库。下面是具体的步骤:

点击File\Source Control\Commit (??C),在出现的界面中输入commit信息,比如“initial commit”,然后点击Commit

现在你需要推送本地master分支到远程origin/master分支。进入File\Source Control\Push并点击Push

因为这是你第一次推送到该存储库,你应该在Remote名字origin/master旁边看到“(Create)”。点击Push按钮,然后Xcode会处理余下工作。

wps_clip_image-6005[4]

一旦推送完成,回到浏览器中,刷新界面,你提交的修改应该会显示在你的GitHub 存储库中:

wps_clip_image-508[4]

你同样也应该看到远程存储库和master分支显示在Organizer\Repositories\Guild Browser project\Remotes:

wps_clip_image-2147[4]

恭喜你,你已经学会如何将本地Git 存储库连接到GitHub上的远程存储库,并将本地修改推送到远端。

现在你已经设置好了GitHub 存储库,你可以邀请别人来克隆你的存储库,接受pull请求,或者仅仅是浏览下你的代码。当其他人推送他们的修改到GitHub origin/master 存储库时,点击File\Source Control\Pull (??X),在弹出界面Remote应该设置为origin/master,选择Choose之后,这些修改将会被添加到你的工程中。

如果要查看这些修改,点击Organizer\Repositories\GuildBrowser,扩展开箭头后点击View Changes按钮。

wps_clip_image-27631[4]

持续集成

Continuous integration (CI)通过一个服务器,该服务器连续不断的检测修订控制系统的变化,自动将你的代码进行构建和测试(甚至是开发)。

当有许多个开发者每天对同一个工程修改很多次的时候,CI就变得非常非常的重要。如果出现了冲突或者错误,每个人都会被立即通知到。最终,一些人打断了构建

了解Jenkins

在本教程中,你将会用到一个开源CI服务器Jenkins (http://)来进行自动构建,测试,和部署被推送到GitHub远程存储库的代码。在本节接下来的部分中,你将对Jenkins进行设置并运行。

安装Jenkins

有几种不同的方法可以在Mac安装Jenkins:

1. 你可以使用Jenkins网站上的安装器,它会作为守护进程启动并且运行Jenkins。这种方式很不错,因为它采用了Mac OS X系统本身的启动系统,但是它会导致你需要做更多的步骤,才能让Xcode的编译正常运行。

2. 你可以在终端里使用WAR文件(Java打包文件类型),它会用内建的servlet容器winstone来运行Jenkins。

3. 你可以把WAR文件部署到你已经建立的应用容器内,比如Tomcat、JBoss等。

在这个教程中,你将会在终端里运行Jenkins,因为这是最快并且最方便的方式。从http://mirrors./war/latest/jenkins.war下载Jenkins War文件。打开一个终端窗口,运行以下命令:

nohup java jar ~/Downloads/jenkins.war httpPort=8081 ajp13Port=8010 >/tmp/jenkins.log 2>&1 &

:以上的命令是假设你的Jenkins WAR 文件在你的下载目录里。如果你把WAR文件下载到了不同的目录,需要相应地更改命令中的路径。

注:你可能会发现为启动Jenkins创建一个别名是很有帮助的。在终端里,或是文本编辑器中显示隐藏文件,打开/Users/(username)/.bash_profile并且输入以下几行:

alias jenkins=“nohup java -jar ~/jenkins.war –httpPort=8081 –ajp13Port=8010 > /tmp/jenkins.log 2>&1 &”

保存.bash_profile, 打开一个新的终端,然后输入jenkins来启动Jenkins。

这会在8081端口上启动Jenkins服务。nohup是一个UNIX的命令,它可以让一个进程在你登出或是shell退出的时候,仍然保持运行状态。

以上的命令也会在/tmp/jenkins.log文件中记录日志。我会尽量去配置与已有的服务不冲突的端口。在浏览器中打开以下URL就能进入Jenkins:

http://localhost:8081/

配置Jenkins插件

在你开始设置任务之前,你需要为Jenkins添加一些东西。打开Jenkins的控制面板(通过 http://localhost:8081)) 并且点击Manage Jenkins\Manage Plugins\Available标签。这里有很多可用的插件,在右上角筛选框中输入Git来进行筛选。

这个就是你想要的:

wps_clip_image-18178[4]

点击Git Plugin旁边的选中框,然后点击Install without restart按钮。

当它完成安装后,你就可以看到以下界面:

wps_clip_image-13536[4]

现在在筛选框中输入Chuck Norris,然后找到Chuck Norris引用插件。

尽管这个插件是可选安装的,但是我还是强烈推荐你们安装。如果你不安装它,Chuck是会知道的!小心Chuck的愤怒:]

注:我的朋友叫我Charlie,但是我的真实名字是Charles。我父亲的中间名字叫做Norris。所以我曾经正式地宣称要把我的儿子命名为Chuck Norris Fulton…但是不幸的是我老婆没让我这样做:)

设置Jenkins的邮件通知

如果有一个SMTP邮件服务器就好了,那么Jenkins可以发送编译错误的通知。但是如果你没有SMTP服务器,你可以使用你的Gmail账户(或是其他任何你喜欢的SMTP服务器)。

打开Manage Jenkins\Configure System,然后在Email Notification部分,输入以下设置(点击Advanced Settings按钮来设置更多选项):

 SMTP Server : smtp.gmail.com

 Sender Email address :

 Use SMTP Authentication

 User Name:

 Password:

 Use SSL

 SMTP Port:465

wps_clip_image-32002[4]

现在通过Test configuration by sending test-email来测试email通知,输入一个email地址,然后点击Test configuration按钮。一旦你确认测试成功,记得按Save按钮来保存你的新设置。

现在你可以收到来自Jenkins关于编译失败的通知。

创建一个Jenkins任务

现在你已经为创建任务做好了准备。打开Jenkins的控制面板,点击New Job,输入任务名称GuildBrowser,选择Build a free-style software project单选按钮,最后点击OK按钮。你现在应该会看到任务设置界面。

Source Code Management部分,点击Git单选按钮,在Repository URL文本框中输入远程的GitHub存储库(origin/master)地址。你的屏幕看起来会像是这样:

wps_clip_image-12378[4]

打开Post-build Actions section,,在Add post-build action按钮中选择Email Notification,输入接收者的email地址,最后选中Send email for every unstable build。你会看到以下内容:

wps_clip_image-28745[4]

如果你安装了Chuck Norris插件,你还可以增加一个构建后动作来Activate Chuck Norris.。这听起来有点吓人!注意,不要破坏了编译!

:Chuck Norris的程序没有版本号,因为他只写一次。如果用户反馈了一个bug或是一个需求,他们不会活着见到太阳升起的。

不要忘了点击保存按钮

点击左侧边栏上的Build Now按钮,确认GitHub的配置都正确。编译后,你会发现编译历史框已有所记录。

wps_clip_image-27397[4]

如果一切正常,编译#1应该为蓝色,表示编译成功。

wps_clip_image-12772[4]

要查看编译期间到底发生了什么,(将鼠标)移到编译历史上,查看Console Output(终端输出)

wps_clip_image-17409[4]

你的终端输出应该如下图所示,说明代码已从GitHub存储库导出到本地。

wps_clip_image-30127[4]

至此,你已经连接上GitHub,并且设置了邮件通知。下面紧接着我们来添加一些感兴趣的功能:测试,编译和上传项目工程到TestFlight。

注:(一个Jenkins有用的提示)要快速的打开任务配置界面,(将鼠标)移到位于屏幕顶端导航栏的任务名称上,从菜单中选择Configure。当查看终端输出时,这很有用。

wps_clip_image-5128[4]

Jenkins自动Xcode编译

让我们更新Jenkins来构建项目。选择Jenkins Dashboard\GuildBrowser job\Configure,在Build部分,点击Add build step,下拉选中执行Execute shell.

wps_clip_image-7298[4]

在命令窗口输入下列代码:

export DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer/

xcrun xcodebuild clean build

你的代码窗口应该如图所示:

wps_clip_image-8051[4]

现在点击保存。让我们点击Build Now来测试以上配置。一旦开始执行,注意了!你可能会被问及是否允许Jenkins运行code sign(代码签署)以便签署你的代码。选择Always Allow

wps_clip_image-11437[4]

如果你错过了弹出的提示(例如, 你正在追逐拿走你iPhone的两岁小孩^_^),你将会在终端输出中看到如下信息:

Command /usr/bin/codesign failed with exit code 1
** BUILD FAILED **
The following build commands failed:
CodeSign build/Release-iphoneos/GuildBroswer.app
(1 failure)
Build step ‘Execute shell’ marked build as failure

如果这发生了,重新运行项目,但是这次不要再错过提示(或者再不要让你两岁小孩拿走你的iPhone)。

当撰写这篇博文时,我真的不得不用find my iPhone来定位我的iPhone。这个小家伙已经把手机塞进他玩具车的后备箱里!!

假设你没有错过提示,那么你会看到输出如下所示:

/Users/charlie/.jenkins/workspace/GuildBrowser/build/Release-iphoneos/GuildBrowser.app
Unable to validate your application. – (null)

这意味着编译成功!你可以安全的忽略“unable to validate(无法验证)”信息  这是已在今年的WWDC上确认过的众所周知的bug。

注:有一款叫做Xcodeplugin的用来构建iOS软件的Jenkins插件,它很不错,但我认为最好了解程序编译期间发生了什么。你可以用一些自己的编译脚本来达到与插件相同的效果。

更重要的是,依赖插件会带来一些风险。假设Apple改变运行机制,导致插件运行不正常,并且插件不再提供更新,如果你知道运行的来龙去脉,那么你依然能够适应。

单元测试

单元测试可以确保正在开发时代码输出保持不变。在建立了一个类将要做什么的期望后,我们编写单元测试以验证这些期望是否正确。单元测试也可以让你逐步看到输出,来逐步修改代码,这使得开发新功能和作大的修改更容易。

在项目中运用单元测试的另外一些好处是:

可靠性  一个很好的测试集,使得bug尽可能的少,尤其是开发开始就一直进行代码测试,验证每一个改变和新编写的代码。

 更加可信的代码 知道了你的代码应该依旧输出相同的结果,能够通过测试,这使得在深入和重构使用了单元测试的大量代码时少费许多脑筋。

 稳定性 – 一旦发现bug,可以加入新的测试,以确保相同的bug不再发生。

Xcode在SenTestingKit框架中内置了单元测试。当编写单元测试时,需注意以下两个方面:

 测试用例 – 单元测试的最小组成就是测试用例,用来验证代码单元的输出。例如,一个测试用例可能集中于测试单一的方法,抑或类中的一小组方法。在Xcode中,所有的测试用例必须以名称test开头。你将会在下面看到一个例子。

 测试套件 – 一组测试用例。这通常是一组用于某个特定类的测试用例。在Xcode中,有一个叫做Objective-C test case class的用来创建测试套件的模板。它产生了一个SenTestCase的子类。

建立单元测试有两个方法:自底向上(单独测试每个方法或类)或者从上而下(作为整体测试应用功能)。这两个方法都很重要  通常比较好的是两者混合使用。

在本教程中,你将集中于一些模型类,使用自底向上单元测试。在iOS 6 by Tutorials中,将有另外一章教你尝试自顶向下法,运用UI自动化,从用户界面到模型代码进行测试。

应用程序VS 逻辑测试target

接下来看一下Xcode中两种可用的类型不同的单元测试。

应用程序单元测试

应用程序单元测试基本上指需要使用UIKit控件或者在主应用程序环境中运行的任何代码。当创建一个包含单元测试的新项目时,这种类型的单元测试target是你得到的默认类型。

在这个target中的所有代码将会在你的应用程序包中运行。通过查看每个target的build settings并且检查Test Host 以及 Bundle Loader的设置,你就能发现不同。

wps_clip_image-16713[4]

逻辑单元测试

目前,这是唯一一种能在命令行中执行单元测试代码的单元测试类型。这个代码是独立于应用之外测试的

这些是测试你自己代码用的单元测试 – 基本上所有这些都不需要在模拟器运行。 对于测试逻辑,网络访问代码,或者你的数据模型类非常有用。

wps_clip_image-4937[4]

从命令行运行测试,注意——没有触摸!

不幸的是,自Xcode 4.5起,我们不被“官方”允许通过xcode build命令运行应用程序单元测试。这令人沮丧,因此你显然能在Xcode中运行应用程序的单元测试。因此,你将在下一节创建一个特定的逻辑测试target。

一些有创意的开发者已经针对Xcode.app内容中的测试脚本做了补丁。本教程中,你将坚持通过Jenkins运行你的逻辑测试并且通过Xcode运行应用程序测试。如果你对那些补丁很好奇,可以看看这些文件:

/Applications/Xcode.app/Contents/Developer/Tools/RunUnitTests

/Applications/Xcode.app/Contents/Developer/Tools/RunPlatformUnitTests.include

当你通过?-U运行单元测试,将默认执行这个脚本:

/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Tools/RunPlatformUnitTests

你将会得到一个错误信息,因为我们不能在模拟器中通过命令行工具运行应用程序单元测试(记住这在Xcode中能成功执行)。

RunTestsForApplication() {
Warning ${LINENO} “Skipping tests; the iPhoneSimulator platform does not currently support application-hosted tests (TEST_HOST set).”
}

一些聪明的骇客已经能运行应用程序测试,但是从Xcode 4.4到Xcode4.5,脚本已经改变了,如果这么做的话结果需自己负责。

添加逻辑测试target

现在你要创建一个新的测试target用于你创建的脚本调用。

在Xcode中,到File\New\Target…\iOS\Other\Cocoa Touch Unit Testing Bundle ,接着点击 Next

wps_clip_image-24511[4]

输入一个以Tests结尾的名字,例如GuildBrowserLogicTests,确认Use Automatic Reference Counting已经勾选,然后点击完成。

wps_clip_image-7471[4]

现在你有一个相同名字的新scheme。为了测试每个控件正常运行,切换到新的scheme(通过Xcode工具栏上Run和Stop按钮旁边的scheme选择器)并运行Product\Test (?-U)

你应该看到构建成功了, 但是测试失败了

wps_clip_image-32218[4]

根据错误信息的显示,单元测试还未被实现。让我们去修正它!

首先,删除默认的测试类,选中GuildBrowserLogicTest.h andGuildBrowserLogicTest.m,点击Delete,接着选择Move to Trash。这样你就不用切换schemes,让我们来修改主程序的scheme,GuildBrowser,让运行Product\Test时包含你新创建的Target。

切换到 GuildBrowser scheme, 并且通过Product\Edit Scheme来编辑 scheme, (或者你可以直接按住 Alt 并点击 Run 按钮)。 在 scheme 编辑器中, 选中 Test 配置, 点击 按钮来添加一个新的 target, 在窗口中选择GuildBrowserLogicTests, 然后点击Add

你的屏幕应该看起来像这样:

你现在准备好给你的测试target添加单元测试类。接着你就能通过jenkins任务调用这个target。在这个盛宴的下一部分你会做到这些。保持学习欲望……和不满足!

何去何从?

在这几天,我们将发布这个教程的第二部分。同时,如果你有任何问题和意见,请加入如下的论坛讨论!

wps_clip_image-19606[4]

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多