在这个 Travis CI 教程中,学习如何设置流行的持续集成服务,并与 GitHub 集成,以便自动运行测试。
作者:Ellen Shapiro
时间:2015 年 9 月 11 日 · 文章(30 分钟)· 中级
原文:https://www.raywenderlich.com/1618-travis-ci-tutorial-getting-started
使用 Travis CI 自动化测试
你有 99 个问题,测试就是其中之一!
开发人员知道,在问题影响用户之前,必须彻底测试应用程序。忘记测试会导致像烦恼的客户一样的复杂情况,在 App Store 中咆哮一星评论,以及因为让简单的错误漏网而引起的瘀伤。
但是如果你必须手动完成,记住在每次提交或合并之前运行测试可能会很困难。什么是时间紧迫的开发人员呢?
持续集成
值得庆幸的是,持续集成 可以节省一天。持续集成(通常缩写为 CI)是在提交更改时自动构建和运行测试的过程。
现在,Apple 有自己的 Xcode Bots 解决方案,它可以在 OS X Server 上运行。但 Apple 的解决方案的缺点是你,是的,你 必须管理整个过程。您必须在服务器上设置和维护 OS X Server 和 Xcode 版本,找出用于查看结果的访问控制,以及处理配置和签名问题。听起来很多工作,对吧?你没有时间做这件事; 你有编写代码,设计应用程序,以及欢乐时光 - 啤酒不会自己喝酒。
和我一起向宇宙大喊:必须有一个更简单的方法!
Travis CI
幸运的是,宇宙听到了我们,并回答了 Travis CI。
什么是 Travis CI?*
通常简称为 Travis,它是一个持续集成服务,对于开源项目是免费的,并且根据您想要运行多少个同步构建,每月收取 闭源项目 费用。它有什么作用?*
Travis 与 GitHub 建立 “钩子” 以在指定时间自动运行测试。默认情况下,这些设置为在创建拉取请求或将代码推送到 GitHub 后运行。
在这个 Travis CI 教程中,您将使用公共 GitHub 存储库和 Travis 的免费版本来设置每次尝试将新更改合并到该存储库时运行的测试。
注意:本教程假定:
. 您已经拥有 GitHub 帐户。如果你不这样做,请 在这里 注册一个免费的。
. Git 已安装在您的系统上。您可以通过打开终端并键入 哪个 git 来检查这一点。如果有结果 - 通常是 /usr/bin/git - 那么你很高兴。如果没有,你可以从网站的 Git 的安装 在这里。
入门
我们开工吧!下载 入门项目,然后打开 zip 文件并将生成的 MovingHelper 文件夹放在桌面上,以便您轻松找到它。MovingHelper 是一个待办事项列表应用程序,正如您可能从名称中怀疑的那样,可以帮助管理与移动相关的任务。
在 Xcode 中构建和运行项目; 你会看到以下内容:
使用选择器从当前日期选择一个不到一个月的日期,然后点击 “* 创建任务”* 按钮。你会看到以下内容:
该应用已创建任务列表。红色部分是过期任务,而绿色部分是即将到来的任务。
查看代码,您将看到已经设置了一些测试。使用 Command-U 快捷方式执行测试,它们将快速运行并传递:
到目前为止一切都那么好吧?现在您已经知道测试正在通过,您已准备好让 GitHub 和 Travis 设置为自动运行它们。
设置 Git 和 GitHub
首先,您将使用入门项目中的文件创建本地 Git 仓库。启动终端,然后将目录更改为桌面文件夹:
cd ~/Desktop/MovingHelper
接下来,初始化计算机上的本地存储库:
git init
接下来,在 MovingHelper 文件夹中添加所有内容 - 因为您已经在其中,只需键入:
git add --all
最后,提交所有代码:
git commit -m "Starter project from raywenderlich.com"
现在一切都在本地提交,是时候在 GitHub 上创建一个公共存储库了。这就是 Travis 将关注的变化。
注意:将此终端窗口保持打开状态,以便稍后再次需要它,这样您就可以保存导航回相应的文件夹。
前往 github.com 并确保您已登录到您的帐户。在页面的右上角,有一个加号,旁边有一个小箭头 - 单击它并选择 New repository:
您将看到一个用于设置新存储库的页面:
拥有者将是你。将 repo 命名为 MovingHelper,给它一个简短的描述,确保它是公开的,并且不要添加自述文件,许可证或 .gitignore
,因为这些都包含在示例项目中。接下来,单击绿色的大绿色 存储库 按钮。您将看到一个页面,说明如何将代码提供给 GitHub。
在浏览器的标签页中打开此页面 - 您很快就会想到它。
设置 Travis
在浏览器中打开一个新选项卡,然后转到 travis-ci.org 开始使用 Travis 的免费版本。右上角是一个允许您使用 GitHub 帐户登录的按钮:
使用此按钮注册 Travis。由于您已经登录 GitHub,因此您无需再次登录。如果您还没有注册 Travis,则需要同意他们要求的权限:
Travis 需要访问读写 Webhooks,服务和提交状态。这样它就可以创建自动 “钩子”,它需要在你想要的时候自动运行。
单击绿色的 “授权应用程序” 按钮。GitHub 会要求您验证密码:
输入您的密码,然后单击 确认密码。现在你正在 Travis“入门” 页面上。
您的头像和 GitHub 用户名位于右上角:
单击要转到 Travis 配置文件页面的内容。您将看到所有公共 repo 的按字母顺序排列的列表。如果您之前没有设置 Travis,则应该取消选中。
向下滚动到 MovingHelper:
轻拂开关将其打开:
那里!Travis 现在正在关注您对 MovingHelper 存储库的更改。
推送到 GitHub
使用新创建的 GitHub 仓库返回选项卡。从 “... 或从命令行推送现有存储库” 部分复制命令:
注意:使用 你的 repo 上的内容,而不是屏幕截图中显示的内容,因为你需要推送到与你的 GitHub 用户名绑定的 remote ,而不是我的。:]
手动或通过单击右侧的剪贴板图标复制该部分的文本,然后将其粘贴到终端并按 Enter 键。这会将您的新 GitHub 存储库添加为 remote 并将所有内容推送到它。
由于 Travis 现在正在观看这个 repo ,它会注意到这个推送,并在所有其他开源构建的行中等待运行。
注意: 在 Travis 的开源版本上构建可能需要一段时间才能运行 - 您基本上与运行开源测试的任何其他人一致。与邮局不同的是,你不能因为假装你的孩子的舞蹈演奏会而迟到而排队。]
每当您的测试运行时,您将收到包含以下内容的电子邮件:
哇!发生了什么?单击 build Build#1 无法 获取失败构建的结果:
底部的警告包含一个特定的行,解释了构建失败的原因:
Could not find .travis.yml, using standard configuration.
那是什么意思?好吧,.travis.yml 文件使用 YAML 告诉 Travis 如何设置构建。由于 Travis 使用多种不同的语言,因此如果没有关于它是什么类型的项目的信息,它就不知道如何构建您的特定项目。
要快速查看需要非常少配置的 Travis 的一些最佳功能,请在命令行中通过在终端中键入以下内容来检查新分支:
git checkout -b travis-setup
终端将确认您创建并签出了一个新分支:
Switched to a new branch 'travis-setup'
接下来,打开您选择的纯文本编辑器。TextWrangler 在这里特别有用,因为它会自动突出显示 YAML 文件的语法,但任何纯文本编辑器都可以使用。
创建一个新文档并将其作为 .travis.yml 保存在您的 仓库 的根目录中。
注意:您可能会收到有关以前缀为 a 的名称的警告 。 被系统保留,但无论如何,使用点 - Travis 将寻找一个文件名为 正是 .travis.yml,这样的点是安全的,在这里使用。
将以下五行添加到新的 .travis.yml 文件中:
language: objective-c #1
osx_image: xcode6.4 #2
xcode_project: MovingHelper.xcodeproj #3
xcode_scheme: MovingHelper #4
xcode_sdk: iphonesimulator8.4 #5
请注意,YAML 将忽略任何带有 # 作为注释的前缀。以下是 Travis 对每一行的处理方式:
- 使用... Objective-C 建立一个项目!?别恐慌!即使您的项目是在 Swift 中,Travis 也只使用该
objective-c
值来了解使用 Xcode 命令行工具进行构建。由于 Xcode 知道如何分辨 Swift 中的内容以及 Objective-C 中的内容,因此您的 Swift 项目会很好。:] - 使用 Xcode 6.4 工具来创建构建,因为您使用的是 Swift 1.2。目前,这需要指定您要使用的 VM 映像 - 在本例中
xcode6.4
。 - 使用指定的 Xcode 项目文件。请注意,如果您要使用 .xcworkspace 构建项目(例如,使用 CocoaPods 的项目),则可以将 xcode_project 参数替换为
xcode_workspace
并使用 .xcworkspace 文件作为值而不是 .xcodeproj。 - 使用指定的方案来决定要运行的测试。由于您的默认方案称为 MovingHelper,因此 Travis 应使用该方案。
- 在 iPhone 模拟器上运行测试,因为这样做不需要设置代码签名(本教程不涉及)。
确保保存 .travis.yml 文件,然后添加并提交给 Git:
git add .travis.yml
git commit -m "Added .travis.yml file"
接下来,将您的分支推到您的远程:
git push -u origin travis-setup
为您的 MovingHelper GitHub 仓库 重新加载网页。你应该看到这样的东西,表明分支已经完成了 GitHub:
单击绿色 比较和拉取请求 按钮。
注意: 如果您没有看到 Recent Pushed Branches,请单击分支名称旁边的绿色按钮。将基本分支保留 为主 分支,但将比较分支更改为 travis-setup,然后单击 “* 创建请求”*。
将拉取请求的标题更改为 Travis 设置:
单击绿色的 创建拉取请求 按钮,Travis 将自动开始工作。一旦您的构建完成,您将在 GitHub 页面上看到类似的内容:
哎呀!你已经添加了像你应该的 .travis.yml 文件,为什么它不起作用?
单击其中一个 Details 链接以查看此构建的结果。新错误会直接导致您遇到问题:
哦!Travis 知道该方案的名称,但由于它是自动创建的,并且未在您的 GitHub 存储库中共享,因此 Travis 无法看到它。通过返回 Xcode 修复它,并从方案下拉菜单中选择 Edit Scheme ...
当方案编辑器出现时,请检查面板底部的 共享 复选框:
单击 “关闭” 按钮,然后添加并提交所有共享数据(包括新的共享方案):
git add MovingHelper.xcodeproj/xcshareddata
git commit -m "Added shared scheme"
再次推送到 GitHub:
git push -u origin travis-setup
由于您已经有拉开请求,Travis 会立即知道您添加了更改并重新开始构建:
构建完成后,您应该看到您一直在等待的内容:绿色!
一切都很好。单击 显示所有检查,对话框将展开,显示已通过的构建:
单击 “* 详细信息”* 链接,您将转到 Travis 的输出。您可以滚动浏览并查看项目构建方式以及测试运行方式的详细信息,但最后一行 - 以及好消息 - 始终如一:
在它旁边带有绿色复选标记的每个项目都是通过测试 - 正如您在最后看到的绿色文字一样,所有测试都在通过!哇噢!
返回 GitHub 页面并单击绿色 Merge pull request 按钮,然后单击 Confirm merge 以正式合并您的更改。
Hello, World!
现在您的测试自动运行,是时候通过向 README 添加 徽章 来告诉其他人您的测试正在通过,该 徽章 显示了 Travis 上构建的当前状态。
在你走得太远之前,确保你 掌握主 分支中的所有内容:
git checkout master
git pull origin master
切换回 travis-setup 分支并将 master 中 的更改合并到其中:
git checkout travis-setup
git merge master
现在合并提交已合并回到 travis-setup 分支,在您选择的 markdown 或纯文本编辑器中打开项目根文件夹中的 README.md 文件。
将以下行添加到文件末尾:
####Master branch build status:
![](https://travis-ci.org/[your-username]/MovingHelper.svg?branch=master)
不要忘记替换 [your-username]
为您的实际 GitHub 用户名。
您刚刚添加了一个图形链接,该图形将是 Travis 根据您在 branch
URL 查询参数中指定的分支的构建状态提供的 “传递” 或“失败”徽章。
将更改保存到 README,然后添加,提交和推送它们:
git add .
git commit -m "Add Travis badge to README"
git push origin travis-setup
返回 GitHub 页面。按照与以前相同的步骤创建新的拉取请求。将此新拉取请求命名为 徽章,然后单击 “* 创建拉取请求”*。
Travis 将再次开展业务 - 由于您没有更改任何代码,测试将继续通过:
再次,单击 合并拉取请求,然后单击 确认合并 按钮以合并您的更改。合并后,您将在主要的 MovingHelper GitHub 页面上看到您的徽章:
打破构建
现在您已经获得了几个传递拉取请求而没有更改任何代码,现在是时候将事情提升到一个新的水平:打破构建。:]
首先让您的 主 分支与您刚刚合并的最新更改保持同步:
git checkout master
git pull origin master
要查看要修复的问题,请构建并运行该应用程序,然后选中其中一个框。建立并再次运行。不再检查该框。哎呀!
当您从测试人员或用户那里获得错误报告时,最好编写一个测试来说明错误并显示错误。这样,当测试运行时,您可以确信该错误没有神奇地再次出现 - 通常称为回归。
让我们确保当您在列表中标记任务时,应用会记住。为此工作创建一个新分支并将其命名 为 - done:
git checkout -b to-done
打开 Xcode 并转到 TaskTableViewCell.swift 文件。您可以看到 tappedCheckbox()
,有一个 TODO
注释而不是实际代码将任务标记为已完成。对于要传递任务状态更改的单元,它将需要对任务的引用和委托以将更改传达给。在插座下面添加这两个项目的变量:
var currentTask: Task?
public var delegate: TaskUpdatedDelegate?
由于单元格被重用,因此在重新使用单元格之前清除这些变量的值,方法是重写 prepareForReuse()
并将每个值重置为 nil
:
public override func prepareForReuse() {
super.prepareForReuse()
currentTask = nil
delegate = nil
}
在顶部添加一行以 configureForTask(_:)
存储当前任务:
currentTask = task
将 TODO
in 替换为 tappedCheckbox()
代码以将任务标记为已完成,并通知代理更改:
if let task = currentTask {
task.done = checkbox.isChecked
delegate?.taskUpdated(task)
}
最后,转到 MasterViewController.swift,然后在 tableView(_:cellForRowAtIndexPath:)
返回单元格的上方添加一行,将其设置 MasterViewController
为单元格的委托:
cell.delegate = self
建立并运行。检查项目,然后停止应用程序。建立并再次运行。万岁,物品仍然被检查!
提交您的更改:
git add .
git commit -m "Actually saving done state"
自动化
现在您已经修复了错误,现在是时候编写 Travis 可以自动运行的测试了。这样,如果事情发生变化,你会马上知道。
首先,在 Xcode 侧栏中选择 MovingHelperTests 组,然后选择 File \ New \ File ... 并选择 iOS \ Source \ Swift File 模板。将此新文件命名为 TaskCellTests.swift,并确保将其添加到测试目标,而不是主目标:
接下来,通过 import
使用以下内容替换现有语句来设置基本测试用例类:
import UIKit
import XCTest
import MovingHelper
class TaskCellTests: XCTestCase {
}
添加一个测试,该测试验证当 TaskTableViewCell
点击 a 中的复选框时,相关任务会更新:
func testCheckingCheckboxMarksTaskDone() {
let cell = TaskTableViewCell()
//1
let expectation = expectationWithDescription("Task updated")
//2
struct TestDelegate: TaskUpdatedDelegate {
let testExpectation: XCTestExpectation
let expectedDone: Bool
init(updatedExpectation: XCTestExpectation,
expectedDoneStateAfterToggle: Bool) {
testExpectation = updatedExpectation
expectedDone = expectedDoneStateAfterToggle
}
func taskUpdated(task: Task) {
XCTAssertEqual(expectedDone, task.done, "Task done state did not match expected!")
testExpectation.fulfill()
}
}
//3
let testTask = Task(aTitle: "TestTask", aDueDate: .OneMonthAfter)
XCTAssertFalse(testTask.done, "Newly created task is already done!")
cell.delegate = TestDelegate(updatedExpectation: expectation,
expectedDoneStateAfterToggle: true)
cell.configureForTask(testTask)
//4
XCTAssertFalse(cell.checkbox.isChecked, "Checkbox checked for not-done task!")
//5
cell.checkbox.sendActionsForControlEvents(.TouchUpInside)
//6
XCTAssertTrue(cell.checkbox.isChecked, "Checkbox not checked after tap!")
waitForExpectationsWithTimeout(1, handler: nil)
}
这是每个部分的作用:
- 创造一个等待的期望。由于委托是测试的单独对象,因此您可能无法立即点击成功块。
- 创建一个符合测试委托的内联结构,它允许您检查并查看它是否被调用。由于您希望此结构告诉您何时满足期望,并根据您传递的值进行检查,因此您将其作为参数接受期望值和期望值。
- 设置测试任务并验证其初始值,然后配置单元。
- 确保该复选框具有正确的起始值。
- 通过发送
TouchUpInside
当用户点击它时将调用的事件,轻击该复选框。 - 确保所有内容都得到更新 - 从复选框开始,通过验证其状态是否已更新,然后等待满足期望,以确保使用新值更新委托。
建立测试,但不要运行它 - 是时候懒惰,踢回去,让 Travis 为你做。提交您的更改并将其推送到远程:
git add .
git commit -m "Test marking tasks done"
git push -u origin to-done
按照您之前使用的步骤创建一个新的拉取请求,并将其命名为 To-Done。正如您可能从不运行测试的指令中猜到的那样,此构建失败:
单击 “* 详细信息”* 链接以获取构建失败的详细信息。一直滚动到底部,您将看到以下内容:
向上滚动一下,查看有关运行测试时发生的崩溃的信息:
D'哦!一个力的展开 IBOutlet
没有用,所以测试崩溃了。那为什么会这样?
如果您考虑 TaskTableViewCell
通常如何创建 - 通过从故事板加载的视图控制器管理的单元重用队列 - 这种崩溃是有意义的。单元格没有从故事板加载,所以 IBOutlets
不要搞定。
幸运的是,这是不是 太 很难解决 - 抓住从实例到单元格的引用 MasterViewController
从故事板实例化,并使用它的 tableView(_:cellForRowAtIndexPath:)
方法来抓住一个有效的单元格。
在顶部添加以下行 testCheckingCheckboxMarksTaskDone()
,将已添加的代码包装在 if
语句中:
var testCell: TaskTableViewCell?
let mainStoryboard = UIStoryboard(name: "Main", bundle: nil)
if let navVC = mainStoryboard.instantiateInitialViewController() as? UINavigationController,
listVC = navVC.topViewController as? MasterViewController {
let tasks = TaskLoader.loadStockTasks()
listVC.createdMovingTasks(tasks)
testCell = listVC.tableView(listVC.tableView, cellForRowAtIndexPath: NSIndexPath(forRow: 0,
. . inSection: 0)) as? TaskTableViewCell
//REST OF CODE YOU ALREADY ADDED GOES HERE
}
接下来,为了确保测试没有通过,如果 listVC
以某种方式 nil
,如果它被击中,则添加一个未通过测试的 else
子句 if let
:
} else {
XCTFail("Could not get reference to list VC!")
}
现在更新您现有的测试代码以使用您刚刚生成的单元格。更换:
let cell = TaskTableViewCell()
有:
if let cell = testCell {
//REST OF THE CODE BELOW SETTING UP THE CELL GOES HERE
} else {
XCTFail("Test cell was nil!")
}
再一次,懒惰,让光荣的自动化为你工作。构建测试以确保代码编译,但不运行它。提交您的更改并将其推送到远程:
git add .
git commit -m "Update grabbing cell for test"
git push -u origin to-done
同样,你有一个现有的拉取请求,所以当 Travis 运行测试时,你应该在你的 GitHub 仓库中看到好消息:
单击 合并拉取请求 按钮,然后单击 确认合并 按钮,您就完成了。
恭喜!感谢您在完成 Travis CI 教程后所付出的努力,现在您可以使用一系列测试来确保在改进应用程序时不会破坏任何内容,并且设置了 Travis 自动运行它们。不再需要手动运行测试 - 现在还有时间欢乐时光:]
接下来呢?
您可以在 此处 下载完成的项目。
本教程仅涉及 Travis CI 可以做的事情。不,它不会给你取咖啡或啤酒,但 Swift 不仅仅是运行测试。
Swift 的进一步能力
. 使用 post-build 挂钩,它可以使用最少的配置自动将构建结果上载到 AWS S3 存储桶。
. 您可以 设置预构建脚本以安装和后期构建从 密钥 链中删除证书 以创建签名的构建。
. 如果您正在创建已签名的构建,则还可以添加 构建后脚本, 以便在合并后测试通过时自动将构建上载到 HockeyApp 或 iTunes Connect。
然而, Swift 并不总是阳光和棒棒糖。
需要记住的几点需要注意:
. Xcode 的新版本通常在公开发布之前不可用。这意味着您无法使用 Travis 构建使用 beta SDK 的应用版本。
. 由于他们有付费服务,Travis 有动力及时升级所有东西。然而,有时候,这种激励并不能使他们足够快地升级以满足每个人的口味。如果您总是需要处于最前沿,请记住这一点。
. 构建计算机可能比本地计算机慢一点。特别是如果您正在使用 KIF 运行 UI 测试,您可能会遇到这样的情况:构建机器的速度慢意味着您看到在真实设备上看不到的竞争条件,或者在您看不到的构建服务器上测试条纹本地。
. 您可以从 Travis 的日志中获得大量信息,但是如果没有设置脚本以在构建完成后将其上载到第三方服务,则无法获取崩溃日志。
. 所有测试都在模拟器上运行。如果你有必须在设备上运行的测试,Xcode Bots 是一个更好的选择,因为它可以在模拟器和真实设备上运行 - 尽管这有责任管理配置和签名。
想知道更多?
如果您有兴趣了解有关与 Travis 持续集成的更多信息,请查看以下文档:
. 通用构建配置指南,可以很好地概述 Travis 构建过程。
. Travis Objective-C 文档,也包括 Swift 项目。
. Travis OS X CI 环境文档,有助于确定 OS X 上默认环境中包含或未包含的内容,以及您可以在 .travis.yml 文件中访问的库存环境变量。