大多数浏览器和
Developer App 均支持流媒体播放。
-
在 Xcode 中进行测试
单元测试是持续验证您的代码能否正常运行的必备工具。了解 Xcode 中内建的利用 XCTest 进行测试的功能。了解如何利用 Xcode 11 中新增的测试计划来组织测试,并在不同的配置下运行测试。探索如何自动进行测试并高效处理对应结果。
资源
相关视频
WWDC22
WWDC20
WWDC19
-
下载
(Xcode测试)
早上好 欢迎参加 Xcode测试演讲 我是Ana Calinov 我将与我的同事 Stuart Montgomery 和Ethan Vaughan一起演讲
在今天的演讲中 我们先介绍用XCTest 在Xcode中进行测试 然后Stuart会讲测试计划功能 最后Ethan会讲 持续集成的XCTest app (XCTEST入门) 让我们先讲XCTest
XCTest是Xcode提供的 一种自动测试框架 配备内置支持可以帮助你 设置并执行测试
测试对于开发任何项目来说 都是非常重要的步骤 测试可以帮助你找到源代码中的错误
你还可以使用测试来编纂需求 意思是测试你所预期的行为 并且你和你的团队之后的工作 也可以通过这些预期得到保证
我们先看一个概述 关于你应该如何考虑规划 任意项目的自动化测试套件 用于测试的金字塔模型 有助于在彻底性、 质量和执行速度之间取得平衡 (测试金字塔) 单元测试是金字塔的基础
单元测试用于验证某一段代码 通常是个函数
这是通过给函数输入变量 并检查它们是否返回预期的输出 实现的
单元测试很短 很简单 并且运行速度也很快
这是我们所有测试的基础 因此你要写很多单元测试 来测试你的所有函数
接下来我们有集成测试 集成测试用于验证较大的一部分代码 这些测试的目标是 离散子系统或类群集 用于确保不同组件可以在一起 正常运作
集成测试位于单元测试之上 因为你要确保 在测试较大的代码段之前 先确保单一函数正常运行
一般来说 你不需要有与单元测试 数量相同的集成测试 集成测试的运行时间稍长 但它们却可以一次测试很多东西
最后是用户界面或UI测试 用于观察app的用户端行为 这会确保你的app 确实实现了你所预期的功能 UI测试的运行时间最长 但它们对于表明 一切都正常运行来说至关重要
UI测试还要求更多的维护 因为你app的UI可能会发生 比较频繁的改变 完整的测试金字塔可以帮助你 在三种不同的测试类型之间进行平衡 并确保测试套件 覆盖了你所需要的功能
那么我们刚讲了如何平衡测试套件 现在让我们讲一下XCTest 所提供的工具 用于帮助你实施测试
XCTest中的单元测试 是针对源代码的所有测试 这包含标准单元测试 以及集成测试
UI测试在app的UI上执行 用于提供app的端对端认证
UI测试也是黑箱测试 因为它们不依赖于 实际支撑你app的任何函数或类
UI测试可以确保 一切都在最末端正常运行
最后性能测试在指定测试中多次运行 用于查看平均时间、 内存使用或给定的其它度量 从而确保你不会在这些区域引入回归 今天我们主要讲单元测试和UI测试
开始测试Xcode项目的 最简单方式是 当开始新项目时选择既包含单元测试 又包含UI测试
在我们的全新的项目中 你可以看到单元测试的目标类 和UI测试的目标类 都在项目导航器中自动创建和显示
还为你提供了模板 用于编写每个测试类 以及其中的测试用例
现在让我们具体看一下 使用XCTest的测试类
类导入XCTest框架时也导入了 要测试的目标
类自身是XCTest用例的 一个子类 从而Xcode可以使用类的方法 执行测试
我们想用作测试用例的每个方法 都必须以测试这个词开头 然后命名最好是暗示它的功能
你还将看到测试左侧有测试菱形 用于显示Xcode可以执行它
在测试内部 断言API用于评估和验证源代码 在这个例子中 XCTAssertEqual 会比较给定它的前两个值 并确保它们相等 如果不等 将导致测试失败
现在一旦我们运行这个测试 我们希望测试通过 那样测试菱形会变成绿色 并且里边会有对勾
我们知道情况并非总是如此 如果测试失败 测试菱形将变成一个 带x的红色菱形 并且会凸显相关代码行
我们还会得到一个报错信息 显示测试中出现了什么错误
我们传给 XCTAssertEqual的字符串 也会显示出来 为我们提供 用于调试问题的更多信息
在这个例子中 我们的源代码可能有一个错误 或你可能初始化为一个错误的值 我们可以返回源代码 修复这个问题 并再次运行我们的测试 直到测试通过
每个测试类模板包含一个setUp 方法和一个tearDown方法 这些代码块可以让你围绕测试 执行任何你需要执行的操作 从而保持测试的特定目的
SetUp在每个测试用例 执行之前调用 在UI测试中 它用于确保 在尝试与app交互 之前app已启动
然后XCTest 会运行你的测试方法 然后tearDown用于 清理你对app的数据 或全局状态所做的任何修改 从而确保测试不会留下任何可能影响 后续测试的东西
现在让我们看一个演示 了解如何给app 编写单元测试和UI测试 (演示)
我们一直在开发一款旅游app 这显示了世界各地不同的目的地 可以帮助你制定度假计划
我想给app添加一个新功能 显示每个目的地 距离我们当前所在的圣何塞有多远
为此我写了一个新类 叫做DistanceCalculator
这个类定义一个城市结构 包含一个带有城市名称的字符串 和一个城市坐标的元组
我当前在字典中存储了城市列表 我计划稍后再迁移这两个数据库
我有一个函数叫做city 它会返回一个可选的城市结构类型 用于在字典中搜索城市
我打算从这个类中使用的主函数 是distanceInMiles 它接受两个城市名称的字符串 并以double返回 两个城市之间的距离 如果词典中找不到其中任意一个城市 将引发报错
最后我有另一个帮助函数 也叫作distanceInMiles 它接受城市结构 并返回城市之间的距离 这个函数使用核心位置框架 因此它替我分担了大部分繁重的工作
要开始编写这个类的单元测试 我已经创建了一个新的测试类 叫做DistanceCalculatorTests
当我开始编写测试时 我希望看到我的源代码 因此我要在下边打开另一个编辑器 然后导航到我的 DistanceCalculator类
我要编写的第一个测试是 测试我的城市函数
因此我要开始编写一个单元测试 并把它命名为 testCoordinatesOfSeattle
对于每个单元测试类 我都将选择一个特定的测试用例 从而确保函数能用
在这个例子中 我要在city 函数中输入Seattle 并确保返回了它的正确坐标
我要做的第一件事 就是通过初始化我的 DistanceCalculator查找计算器
现在我可以开始编写并调用函数了
但有一点要记住 city返回一个可选的城市结构 因此我想确保我得到的返回值不是无
为此 我可以使用这个API 并尝试使用XCTUnwrap 来确保返回值有效
然后我可以对 Seattle调用计算器
现在我得到了一个报错信息 因为看起来出现了一个报错 但没有被处理
如果city的返回值为无 然后我必须确保我的测试用例 也适当地显示出了这个问题
现在我的city变量 用于返回Seattle的值 我可以使用我的断言API来确保 经度和维度值都正确
现在我要点击测试菱形运行测试
这将会启动app 运行测试 并告诉我们发生了什么
看起来测试成功了 太棒了
我现在可以给类编写另一个测试了 我要测试我的 distanceInMiles类
我要把函数命名为 testSanFranciscoToNewYork 具体看看我的功能性返回
在这里我要做的第一件事 就是通过初始化DistanceCalculator 查找另一个计算器
但在这一点上 我的代码产生了重复 因为我必须在每个测试用例的开始 都执行这个初始化
因此 我要声明一个类变量…
叫做calculator 从而确保在每个测试开始之前 我的setUp函数 可以对它进行初始化
现在我可以开始编写我的测试了
我要以英里为单位定义距离 通过尝试从函数中 调用distanceInMiles 实现从San Francisco到New York
然后我要使用我的断言API来确保 距离是正确的
我要运行从测试菱形中运行测试
看起来这个测试失败了
我可以查看报错信息 从问题导航器中查看失败信息
这一次我们的测试运行了 并且我们得到了报错信息 实际测试失败了
看起来我们所期待的和用于对比的值 比我们实际上所查找的值要精确得多
在这个例子中 我不关心这个精确度 因为我只想给用户显示 两个城市之间的距离的整数 因此我可以添加一个精确度参数…
替换等于一 这将允许 XCTAssertEqual 宽松处理并允许数值加减一 但仍能通过测试
我要再次编写我的测试 并确保测试通过
太棒了
目前我已经给单元测试类 写了两个测试 但这两个测试都接受 对函数的有效输入 并检查是否返回了有效输出 但我还想检查函数的一些 其它测试用例 我还想确保在我的类中 正确地处理了报错
因此我要编写的下一个函数 将是一个负面的测试用例
我不希望Cupertino 包含在城市数据库中 因为我只考虑大城市 而Cupertino并不是大城市
因此当我调用Cupertino时 我希望能产生报错 表明城市在数据库中未知
我可以使用XCTAssertThrowsError 实现
然后我可以使用一个闭包 来查看具体的报错
并把它与XCTAssertEqual 相比较 从而确保它们是正确的
现在我已经编写了三个测试 我想一次运行三个测试 从而确保一切都运行无误 我可以进入测试导航器 这将给我按行显示我项目中的 所有不同的测试目标 测试类和测试用例
我可以任意选择一个级别 并在此之下运行所有测试 因此如果点击DistanceCalculatorTest 旁边的播放按钮 它将运行全部三个测试 我的Apple启动运行它们 并且所有的绿色对勾 意味着测试都通过了
我还可以命令点击不同的行
从而选择运行不同的值 或运行不同的测试类别 如果你不想一次运行所有测试的话
通过情景点击 我可以选择运行它们
如果我选择运行一个子集 然后稍后在我修复一些问题之后 我想重新运行同一个子集 我还可以进入产品菜单 点击实施动作 并选择重新运行上一次运行的测试
现在我已经给我的类编写了一些 单元测试 我想在UI中实施它 我要通过显示 distanceText 并运行我的类来实现
在城市名称下面 我们有用于显示这些城市 距离我们当前位置有多远的距离
我们创建了一个新的UITest类 叫做DiscoverUITest
我们的UITest类 需要两个东西来填充 失败后继续被设为假 一旦UI测试失败 通常意味着我们进入了一个 非预期的UI状态 我们有可能不能再与任何东西 进行进一步交互了 因为我们不知道屏幕上 实际发生了什么
我们还想确保app 在我们尝试与之进行交互之前 已经启动了
我们可以开始编写我们的UI测试了 就跟我们编写单元测试一样
我要编写 testMilesToParis 目标是打开app 滑动到Paris图标… 然后确保所显示的距离是正确的
我要做的第一件事 是实际确保当我们开始测试时 我们处于Discover标签中 我可以通过查找app的 UI中的元素 并与之进行交互来编写UI测试 在这个例子中我要查找一个叫做 Discover的标签栏按钮
然后我要轻触它 从而确保我们处于正确的标签上
在我们执行的每个UI动作之后 我们想验证现在显示正确的屏幕 因此我要确保 San Francisco在屏幕上可见 从而确保我们处于所预期的状态中
我要使用XCTAssert语句 来确保San Francisco 一个静态文本 isHittable isHittable 将确保元素存在 并确保它在屏幕上显示 从而我们可以与它进行交互
现在我要做的下一件事就是向左滑动 这张图片 到达Paris
我实际上不确定如何与这张图片 进行交互 因为它们可能有一个自定义标签 我不确定如何定义它 因此我可以使用调试器来获得 关于app的UI的更多信息
我要在第26行设置一个断点 然后从测试菱形运行我的测试
Apple启动点击 Discover 确保San Francisco可见 然后在调试器中暂停
在调试器中 我们可以获取关于app的更多信息 我们可以通过使用po app 来打印具体的视图等级 从而获得这些信息
在这里我们有一个app中的 所有UI元素的列表 但是这有点多 因此我要进一步指明我只想打印 我app中的所有图片
太棒了 现在我们有一个 所有图片的列表了 看起来San Francisco 就是我想要的那个 我要复制字符串并关闭调试器
然后把我的sfImage定义为 带这个标识符的图片
现在我可以调用这个查询 来实施向左滑动
一旦我完成这个操作 我想确认Paris实际在屏幕上可见 从而UI中没有任何变更 会中断这个测试
因此我可以使用XCTAssert 来确保Paris可点击
最后我想确保显示了正确的距离 因此我要使用另一个 XCTAssert语句来确保5586英里 一个静态文本 可见
现在我们可以从测试菱形 运行我们的测试了
我们会看到一旦我移除断点之后
app启动并执行每一个步骤
我们将看到app启动 我们按Discover 查找文本 向左滑动 然后确保正确显示了所有字符串
在这个测试中还有另一件事要考虑 即我们正在查找一个静态文本 恰好是5586英里 无论何时当你运行这个测试时 你可能要假装或模拟你的位置 正好位于San Jose 否则距离会根据你的实际位置 而发生改变
现在我们要返回到幻灯片中 讲一下项目中的测试组织
当开始编写测试类时 你要从两个测试目标开始 一般来说 一个用于单元测试 一个用于UI测试
单元测试和UI测试必须按类型分开 因为它们在app上的执行方式不同
每个测试类… 测试目标将包含测试类
你的测试目标可以拥有许多 必要的测试类来测试你的app
然后你的测试类包含每个测试用例 同时你的单元测试目标 和UI测试目标 可以完全测试你的app
但有一些情况你需要更多的测试目标 你的项目变得越来越复杂 你可能想要一个新… 创建一个新框架 这个框架应该有自己的单元测试目标 其中包含它自己的测试
此外 你用于在Xcode中创建 和编写测试的Swift程序包 已经定义了测试目标 这些测试目标在Xcode中 与任何其它单元测试目标的用法一样
最后 一旦你对每个测试目标 都重写了一个完整的测试 你可能会考虑测试实际上是否 会覆盖所有的源代码 为此你可以使用代码覆盖率 (代码覆盖率) 代码覆盖率是Xcode XCTest中的一个功能 它会测量并显示在测试运行过程中 每行源代码被执行的次数
在启动这个功能并运行测试后 你可以进入报告导航器并选择 所运行测试的覆盖率数据
你可以在那里看到一个列表 包含每个测试目标和测试类 以及表示该部分 实际执行了多少源代码的百分比
你可以选择每个测试类切换到文件
当在源文件中打开覆盖率数据时 源代码编辑器槽位于右侧 显示当你运行测试时 表示该行被执行了多少次的一个数字 你还可以悬浮在数字上 直接在源代码编辑器中查看信息
被执行了的代码行将变成绿色 在测试过程中没有被击中的代码部分 将以红色突显
你还可以查看综合信息 显示在测试过程中 没有被击中的单一代码路径 比如从未被选中的条件句 代码覆盖率工具 总的来说给你提供关于测试的 更多信息 可以帮助你识别你可能想为之编写 更多测试的区域
当向版本库提交新工作时 请包含代码以及对代码的测试 确保一切都有品质保障 并检查代码覆盖率 从而确保你没有遗漏任何东西
如果你感觉测试没有完全覆盖 你所做的修改 可能是时候返回并编写更多的测试了
你将通过提早编写测试来最大化地 利用测试 通过拥有与你的源代码配套的 测试套件 你可以确保你所编写的每个新功能 都可靠 并且按预期的那样实现功能 请记住 测试是一个持续的过程 对于维持app的正常运行来说 至关重要 现在我要邀请Stuart上台来 讲一下如何充分利用 Xcode中的测试
谢谢Ana 现在你已经了解了Xcode中的 测试的基本信息 我想讲一下Xcode 11中的 一个新功能叫做测试计划 它会帮助你最大限度地利用测试
无论你是否刚开始编写测试 或如果你的项目已经有一套很大 并且很强健的测试套件了 我们要跟你们分享一个建议 可以帮助你们最大限度地利用测试 我们实际上推荐你们以不同方式 多次运行测试
现在即使你没有对测试进行任何修改 如果你在测试选项中更多地利用 Xcode的创建 及其高级功能 你可以获得从测试中得到更多信息 并捕捉更多报错
让我们一起来看一个例子
假如我们一直在开发的app 针对许多不同语种进行了本地化
现在我们已经了解了 如何给app编写UI测试
现在一旦我们进行UI测试 当我们以我们开发app的语言 运行测试时 测试很有可能会成功 在这个例子中是英语
但想象一下有一天我们发现了一个 报错 只存在于特定语种之中 那个语种的本地化字符串丢失了 并使用了一个占位符字符串替代 那就破坏了UI布局
现在一旦我们意识到这个问题 我们可以调整Xcode设置 从而手动运行该语种的UI测试 如果我们这样做了 我们可能会看到UI测试失败 当然 如果我们没有那么做 我们就有一个很好的机会 来编写一个新测试 用于重现问题和失败 直到我们修复了报错
但一旦我们修复了那个问题 并且我们有一个覆盖这个问题的测试 理想情况下 我们应该总能运行 这个语种的测试 除我们开发app的语言之外 从而确保app不会再次发生中断
这只是其中一个例子 但还有其它情况 只有当你每次以不同方式多次 运行测试时才可能捕捉到那些报错
比如你可能选择按字母顺序 和随机顺序运行测试 因为按字母顺序运行测试 对于查找测试方法之间 隐藏的依赖关系来说很有帮助
或你可能想使用一个以上的 Sanitizer来运行测试 比如Address Sanitizer 和Thread Sanitizer
如果你不熟悉的话 我稍后会解释这些是什么东西
或你甚至可以在每次测试时 改变任意命令行参数 或环境变量 如果测试时你要测试的代码 需要修改或模拟特定的东西的话 这会很有帮助 比如使用网络服务器的测试版 或也许模拟数据集
Xcode允许你配置各种选项 关于app如何使用方案编辑器运行
你可以访问参数 选项或诊断标签 从而控制如何启动app的各种东西
但这只允许你使用你所选择的 设置来交互性的运行一次app 无论你选择了何种设置
我们真正想要的并且我们一直在讲的 是能多次运行测试的能力 为此 我们在Xcode 11中 引入了一个新功能 叫做测试计划 (测试计划) 测试计划允许你以不同设置 多次运行测试
使用测试计划 你可以在一个地方 定义你所有的测试变化 然后你可以在多个方案中进行共享
现在如果你之前复制了方案 从而你可以多次运行测试 你可能想撤销它 并使用一个测试计划 把多个方案合并为一个方案
Xcode中以及xcodebuild中 都支持测试计划 可以在持续集成服务器 和Xcode服务器中使用 在现有项目中采用测试计划非常简单
我们别一直讲这么多了 让我们返回到演示项目中 给你演示它是如何运作的
(演示 使用测试计划)
好的 返回到我一直在做的项目中 我先给你展示一下测试计划 点击我项目中的新测试计划文件
在这里我可以看到 有关我的测试计划的所有详情
我可以看到所有的测试 首先是测试目标 然后是测试类 然后是每个类中所包含的 全部测试方法
现在使用这个视图 我可以了解一些不同的信息 我可以看到包含所有测试的完整列表 当然了 或如果我想查找特定的测试 我可以使用它… 筛选字段来进行搜索
或如果我出于某种原因 需要暂时禁用一个测试 比如说 如果这个测试目前不起作用 我只需要在已启用栏中 取消选中它即可
我还可以修改与测试目标相关的设置 点击右侧的选项按钮即可实现
在这个例子中 我恰好知道这个测试目标 是我的UI测试目标 并且它确实会受益于 在多个克隆模拟器上 并行运行它的所有测试 那样测试的运行速度会快的多 我要在这里启用它
接下来我要进入测试计划的配置标签 我可以在这里控制 测试如何运行以及运行多少次
左侧有一个列表 叫作测试配置列表 顶部还有一个标签叫做共享设置
我可以在共享设置中控制… 测试运行中每次测试都通用的选项
如果我们看一下 我能控制测试计划中的哪些东西 我可以设置许多东西
我可以修改不同参数 关于测试程序应该如何被启动
我可以修改关于本地化的设置
或改变UI测试截图要保存多长时间
我可以修改测试执行顺序 启用代码覆盖率 或启动比如运行时间Sanitizer 或内存诊断这样的东西
现在你可能注意到这里其中某些是 粗体文本 比如环境变量这一行 那表示我已经给定它一个自定义值 在这里我提供了一个运行测试时的 自定义环境变量
我把测试自定义为 总是按随机顺序运行自定义环境变量 而不是按字母顺序
在这个测试计划中 我真正想要做的是修改它 使它像我刚才提供的例子那样运行 从而它会使用不同语种运行两次
我可以通过添加第二个配置实现 因为我要以不同语种运行它 我要给我所要使用的语言提供一个 自定义名称 即德语
既然到这儿了 我要把第一个配置的名称 自定义为美语
在美语配置中 我实际上不修改任何东西 它拥有所有默认值外加共享设置
但在德语配置中 我要自定义语种和地区
我想指出因为我刚才编辑了 配置 在弹出菜单中 我在顶部看到了一个额外的标签 是计划默认值 这个标签表示 它要从测试计划的共享设置层级 继承的值 因此如果我想恢复这个自定义 并返回到它所继承的值 我只需要选中这个即可
好的 现在我按我的意愿 配置好了测试计划 接下来我要介绍 可以在余下的Xcode中 使用测试计划的几种方式
我要进入我一直在做的一个事件… 一个单元测试文件 叫做EventTests 它测试我app中的事件结构
它只对结构进行几次小的单元测试
如果我点击这个测试文件中的 任意测试菱形 因为我已经给测试计划 配置了两个配置 那将总共运行两次测试 如果我想运行所有测试的话 这特别棒 特别是在我的持续继承服务器上 运行测试时 但当我开发测试时 我可能不运行…不运行这么多次 因此我可以选择只运行一个配置 通过选择点击测试菱形即可实现 在这里我看到一个菜单只有… 那么我可以选择一个配置
我可以…是的 谢谢
我还可以在测试导航器中实现 如果我在测试导航器中控制点击 任意测试 我可以看到一个类似的菜单 可让我 运行所有配置或只运行一个配置
既然到这儿了 我还想提一下 测试导航器现在显示… 当前哪个测试计划是活跃的 我的方案中只有一个测试计划 但你可以有许多测试计划 我们稍后再讲 拥有多个测试计划的好处
好的 现在我只想运行 全部配置的单元测试
现在我们看到Xcode快速创建了 我的整个项目 然后在模拟器中两次运行我的测试 已经完成了 看起来至少存在一个问题 让我们去看看具体信息
我可以通过点击报告导航器
并进入最新测试动作查看测试详情
在这里我们可以看到大部分测试 都成功了 因此它们有绿色对勾标记…
其中一个测试出现了某种问题 它有一个红色图标 图标上有横杠
测试报告给我显示了所有详情 关于测试会话中发生的一切 如果我展开这个 我可以看到… 看起来这个测试方法 在一个配置中成功了 而在另一个配置中失败了
如果我进一步打开它 我可以看到具体问题 看起来这个测试方法 接收了英语文本 但它应该接收德语文本 看起来这是个问题 我需要返回到我的… app代码或测试中 并进行相应的调整 我稍后再做
在我完成之前 我想讲一下我们对这里的测试报告 所做的一些其它改进 如果我只想查看在两个配置中 拥有混合状态的测试方法 比如这个 我只需要点击 范围栏中的混合按钮即可
或如果我只想查看特定配置中的结果 我只需要点击测试配置弹出框 并选择其中一个配置即可
好的 这就是Xcode中的测试计划 现在让我们返回到幻灯片中
现在你已经实际了解了测试计划 我想提一下关于测试计划 是如何运作的一些细节
测试计划文件实际上就是个 JSON文件 以.xctestplan 为文件扩展名
它包含你要运行的所有测试 以及描述测试如何运行的 所有测试配置
测试计划文件包含在你的常规项目 结构中 并且它可以被一个或多个方案引用
现在测试配置 还描述整个测试计划的测试的 单一运行
每个测试配置都有一个 可自定义唯一名称 给项目中的每个测试配置 都命名一个有意义的名称 是个很不错的主意 因为我们将在比如我们之前看到过的 测试菱形弹出菜单 和测试报告这样的地方看到那个名称
现在每个测试配置都包含 关于如何创建并运行测试的所有选项 它们可以从测试计划的共享设置层级 继承任意通用选项 因此如果任何设置 在每次运行测试时设置都相同 你可以在一个地方定义它们 而不需要重复定义
因此如果你好奇的话 这是你可以在每个测试配置上 进行设置的所有选项的完整列表
你可以从我刚才所展示的 测试计划编辑器的配置标签中 找到这个列表
那么你可能在想 我要如何开始使用测试计划呢
如果你有现有项目 你首先需要把它转换为… 把方案转换为使用测试计划
为此 首先要编辑方案
然后进入方案测试动作
在那里你可以看到一个按钮是 转换为使用测试计划
点击这个按钮将显示一个表单 提供你可以转换方案的不同方式
第一个选项是从方案的现有设置中 创建一个全新的测试计划文件
如果这是你要转换的第一个 或唯一的方案 你很可能会选择这个方式
但另一个选项是选择项目中的 现有测试计划
如果你选择这个 它会给你显示一个表单 让你在工作空间中 选择一个现有测试计划 如果你正在转换的方案… 如果你已经把一个方案转换为 使用测试计划了 并且你想以不同方案分享同一个计划 这是个不错的选择
且如果你已经从零开始创建了一个 测试计划文件 你也可使用这个选项
好的现在我们已经了解了 什么是测试计划 并且你已经了解如何开始使用 测试计划 我想提供一些你可以在自己的项目中 使用测试计划的潜在方式
这是一个你可以创建的测试计划的 一个基本示例 (潜在用例) 每个红色方框代表计划中的一个配置 第一个启用了 Address Sanitizer 另一个启用了 Thread Sanitizer
现在如果你不熟悉这些的话 Sanitizer 是潜在Xcode中的工具 用于输入你的代码 并帮助你识别手动难以重现的错误
有些sanitizer 比如这两个 可以合并使用 如果你以这样的方式构造测试计划 你仍可用这两个sanitizer 来运行测试并从中受益
要从这个测试计划中获得更多价值 如果你的项目包含C 或Objective-C代码的话 你还可以通过在每个配置中 启用未定义的Behavior Sanitizer 来扩展计划
你可能注意到未定义的 Behavior Sanitizer 在两个地方进行了设置 它在每个配置中进行了重复设置
把这个设置向上移到 计划的共享设置层级更好
然后计划中的每个配置 将自动继承这个设置
现在有一件事要注意 如果你配置了这样一个测试计划 带有手动不兼容sanitizer 如果你运行计划中的两个配置 Xcode需要创建两次项目 为每组sanitizer分别创建一次项目
这对于持续继承环境来说很棒 你不用担心需要较长时间来创建测试 因为它们执行的是更彻底的测试
但测试计划并不只是选择不同的 sanitizer 正如我在之前的演示中所展示的那样 你还可以配置附带配置的计划 配置可以代表不同的语种或区域 比如我在这里选择了美国、韩国 和意大利 并没有可以拥有多少配置的限制
现在如果你配置了一个像这样的计划 你可以用它来运行你的UI测试 然后你可以从这些测试中收集截图 通过在共享设置中启用新的 本地化屏幕截图功能即可实现
本地化截图时 Xcode 11中的新功能 可以让你的UI测试保存所有截图 甚至还会保存测试成功的测试的截图
它会收集关于你app所使用的 本地化字符串的数据
这就可以让你引用截图作为情境 当你本地化app时 或如果你已经完成了本地化 你可以在App Store中列出 世界各地的截图
要获取更多此类信息 以及其它本地化改进 请在WWDC网站上查看我们的… 创建优秀的本地化体验演讲
最后我想强调一下 你可以在一个测试计划中混合并匹配 这些设置 只要对你的项目有意义就可以
比如你可以以三种截然不同的配置 构造这样一个测试计划
第一个配置主要关注内存安全性 因此它有 Address Sanitizer 以及Zombie Objects 内存设置
第二个配置是关于并发性 它有Thread Sanitizer 和Undefined Behavior Sanitizer 并且它每次都以随机顺序运行测试
然后最后一个配置是当运行测试时 收集额外的诊断 它通过给被测试的代码 设置自定义环境变量实现 从而可以出发更多的日志采集
它还会启用 保留所有自定义文件附件的选项 甚至会保留测试成功的测试的 自定义文件附件
这是一个非常复杂的例子 但它却展示了 测试计划的能力和灵活性 你可以按照你的意愿来运行测试
那么这就是测试计划 是Xcode 11中的新功能 通过以不同方式多次运行测试 可以让你最大限度地利用测试 获得更多利益 现在我要把舞台交给Ethan 他会分享使用Xcode 进行持续集成的一些方式 谢谢
(持续集成流程)
谢谢Stuart 要利用测试计划的全部能量 你很可能想在许多不同配置下 运行测试 有一个很不错的地方可以实现 这个功能 即在持续集成中 这会自动化创建和运行测试的过程 当你坐在办公桌前 你主要关注的是让测试成功 持续集成会在所有设备上 运行所有测试 为你提供最大程度的覆盖率
Xcode的持续集成 有两个主要的可选方案 第一个方案是Xcode服务器 它是直接嵌入到Xcode中的 通过Xcode服务器 你可以轻松地设置一个框 使用最少量的配置创建并测试app
第二个选项是创建你自己的 持续集成设置
这个选项更高级一些 如果你有自定义需求 或需要与现有基础结构进行集成的话 适合采用这种方案
如果你确实需要进行自定义设置 你是幸运的 Xcode配备强大的工具 你可以用于创建自己的自动化操作
在这个部分中 我们主要讲第二种方案 并了解如何创建一个完全自定义的 持续集成管道
端对端 我们的管道由四个步骤组成 每一步都包含不同工具的使用
第一步 我们要在专用的创建器机器上 创建我们的测试
第二步 我们要在一套设备上执行 我们所创建的测试
这些设备将与第二台机器相连接 我们留出第二台机器用于运行测试
前两个步骤将生成一些创建 和测试结果 这些结果将作为下两个步骤的数据源
第三步 我们主要关注 测试失败的创建和测试结果 从而填充我们最喜欢的问题追踪器
最后第四步 我们要随时间追踪我们的代码覆盖率 从而了解我们在整体测试覆盖率方面 做得怎么样
让我们从前两个步骤开始 创建并运行测试
对于这些任务 我们将使用xcodebuild Xcodebuild是 Xcode的命令行界面 它是整个流程的核心力量
在xcodebuild背后是 xcodebuild系统 和XCTest
通过xcodebuild 有两种方式可以运行测试 第一种是在同一个调用中创建并测试
为此你要使用测试动作 传入你要测试的项目的名称和方案 以及测试运行的目的地 (用XCODEBUILD 运行测试) 第二种是创建然后测试 这会在xcodebuild的 两个独立的调用中 实施创建和测试动作
这个功能的一个很重要的用例是 让一台机器专用于创建 另一台机器专用于运行测试 这是我们尝试要实现的流程
要实现这个流程 你首先要调用用于测试动作的创建 并传入与之前一样的参数
这既会产生用于测试的创建产品 还会产生一个 xctestrun文件 Xctestrun文件是一个清单 描述创建产品 并说明xctestrun 在测试时要做什么
接下来 不通过创建动作调用测试 传入之前生成的 xctestrun文件
这将会实际上执行测试
实际上你可以构建自己的 xctestrun文件 可以让你更容易控制在测试过程中 所发生的事 而不需要创建
如果你想了解更多 关于这些文件的格式 请查看主页
同时请注意 Xcode版本不同 格式可能也不同 一般来说 请使用 Xcode的同一版本 来创建和运行测试
提到运行测试 xcodebuild支持同时 在多台设备或模拟器上运行测试
这可以最大范围的覆盖各种设备类型 和尺寸
这对于UI测试来说尤其有用 因为app的UI很可能 因为尺寸不同而不同
如果你想了解更多 关于xcodebuild 支持多个目的地的信息 请查看2018年的 测试中的新功能演讲
目前我们已经讲了 xcodebuild的基础知识 以及如何创建并运行测试 现在我想讲一下 测试计划特有的一些选项
如果你有一个方案是有多个测试计划 你可以使用显示测试计划选项 把所有测试计划列出来
如果你有一个方案有多个测试计划 可以开启一些引人注目的流程 比如你可以有一个 运行时间长的测试计划 包含一整套测试 以及一个运行时间短的测试计划 只有几个冒烟测试
如果你选择有多个测试计划 其中一个测试计划将被作为 默认测试计划 你可以给它配置 方案编辑器的测试动作 默认计划是xcodebuild 将运行的计划 除非你另有说明
要覆盖默认的测试计划 可以使用测试计划选项 传入你想要运行的计划的名称
通过以上这些 我们了解了xcodebuild 我们可以开始在我们的管道中填写 一些空白了
从创建器机器开始 我们使用xcodebuild build-for-testing 来产生我们所需要的build产品 和xctestrun文件
这将被传到运行器机器上 运行器机器将调用xcodebuild test-without-building 在我们的设备上执行测试
这两个步骤产生 build和测试结果 这是我接下来要讲的内容
即结果捆绑包 今年关于结果捆绑包 我们有一些很棒的东西要与你们分享 (结果捆绑包) 首先 什么是结果捆绑包? 结果捆绑包是由Xcode 生成的一个文件 包含结构化数据 描述创建和运行测试的结果
它包含资产比如创建日志 显示编译了哪些目标和源文件
测试报告显示哪些测试通过了 以及哪些测试失败了
代码覆盖率报告显示所运行的测试 覆盖了哪些代码
以及由测试使用 XCTest附件API 所创建的所有测试附件
要如何生成结果捆绑包呢? 只需要给xcodebuild传递 结果捆绑包路径选项即可
现在我们知道如何生成结果捆绑包了 我们还可以填充另一个遗漏的东西
我们要给Xcode创建调用 添加结果捆绑包路径选项 从而开始生成这些创建和测试结果
结果捆绑包已经存在一段时间了 但在Xcode 11中 我们彻底 重新设计了底层的文件格式 这带来了一些好处
首先 新格式经过高度优化 可以在磁盘上高效运行 在我们自己的测试中 我们发现结果捆绑包 与之前的格式相比平均缩小了四倍
这在持续集成中尤其有用 在持续集成中 结果捆绑包可以 以非常高的速率生成和存储
第二 现在可以直接在Xcode中 打开结果捆绑包了 这就可以让你轻松地深入查看 集成的结果
第三 我们第一次提供一种 以编程方式访问结果捆绑包的 内容的方式 我们可以在自己的持续集成设置中 利用结果捆绑包的内容
要在Xcode中打开结果捆绑包 双击文件 即可使用你已经很熟悉的UI 来浏览它的内容 请看测试报告中失败和成功的测试 在创建日志中深入了解创建失败 并在代码覆盖率报告中了解 在覆盖率方面做得怎么样
谢谢 要以编程方式访问结果捆绑包的内容 你可使用Xcode 11的新命令行工具 叫做xcresulttool
Xcresulttool 给你提供结果捆绑包中 所含结构数据的完全权限
它把这个数据作为JSON提交 而JSON的格式已经被公开记录 和版本控制了
我们要在下一步中 利用xcresulttool 给问题追踪器填充 在创建和测试过程中所发生的 所有失败
要提取创建失败 使用get命令调用 xcresulttool 传入ResultBundle路径
在接下来的JSON输出中 你可以发现创建失败嵌套在 其中一个对象中
每个创建失败都包含失败信息 以及源文件和创建失败的行编号 (提取创建失败和测试失败) 测试失败也嵌套在JSON内 其中包含失败的测试的名称 以及断言信息
如果你没有100%按这些步骤进行 也不要担心 就像我之前提到的那样 xcresulttool的 一个最大的好处是 它生成的JSON是公开记录的 事实上 工具自身可以使用格式 描述命令 描述JSON的架构
架构列出了可以在输出中呈现的 所有可能的对象类型 因此我鼓励你们当你们编写自己的 自动化测试时 参考一下这个列表
最后但并不是最不重要的 请查看工具的主页获取更多信息
通过我们新开发的 xcresulttool 我们现在可以进入第三步了 我们要用xcresulttool get从结果捆绑包中 提取那些创建失败和测试失败 并把它们放到我们的问题追踪器中
目前我们已经做了很多操作了 但我们还有最后一个步骤要完成 我们想随时间追踪我们的代码覆盖率 用于了解覆盖率是否有所下降
为此 我们要使用另一个命令行工具 叫做xccov
Xccov可以让你以编程方式 访问代码覆盖率报告 可以是人可读的文本或JSON
要使用xccov浏览覆盖率报告 就要调用浏览命令 并给它传递结果捆绑包 (用XCCOV 浏览代码覆盖率报告) 在随后的输出中 你可以看到每个目标的行覆盖率 源文件和项目中的函数或方法
现在简单地浏览覆盖率报告 可能并不完全是你想要实现的功能 如果你还想比较两个报告 用于了解覆盖率是否增加了或减少了 你可以使用diff命令
把路径传给工具的两个结果捆绑包 这将生成类似这样的输出
在这个例子中 我们可以看到 AppDelegate文件的代码覆盖率 在两个结果捆绑包之间增加了50%
跟xcresulttool一样 xccov也有一个主页 请查看xccov主页获取更多信息
这样我们终于完成了最后一步 我们将使用xccov 从捆绑包中提取代码覆盖率 用于追踪我们的进度
太棒了 我们的持续集成流程完成了 使用xcodebuild 创建并运行测试 用xcresulttool 来提取创建失败和测试失败 并使用xccov来浏览代码覆盖率 我们创建了一个完全功能性的 端对端管道 自动化我们的app的测试流程
希望这能让你们了解了一些 使用Xcode配套工具 有多大的能力和灵活性 我们只讲了其中一种可能的流程 但通过这些创建代码块 天空才是真正的极限
今天我们讲了很多内容 让我们快速回顾一下 我们讲了哪些内容
我们先介绍了Xcode中的测试 了解了如何用XCTest 编写单元测试和UI测试 以及如何运行它们以捕捉错误
接下来我们了解了测试计划 这是一个新功能 可以让我们更好地管理我们的测试 以及在不同配置下多次运行测试
最后我们了解了我们可以用于 创建自定义持续集成管道的工具
如果你想了解更多 请从developer.apple.com中 复制这几张幻灯片 请一定要查看 Xcode 11的版本注释
最后如果你有兴趣了解 XCTest中 用于测量代码的性能的新API 请查看今天稍后举办的 延长电池寿命和改善电池性能演讲
请参加我们的演讲 祝你们度过一个愉快的WWDC
-
-
正在查找特定内容?在上方输入一个主题,就能直接跳转到相应的精彩内容。
提交你查询的内容时出现错误。请检查互联网连接,然后再试一次。