# iOS开发之Xcode测试苹果官方文档翻译（下）

语言：zh-CN
原文：[iOS开发之Xcode测试苹果官方文档翻译（下）](<https://allluckly.cn/%E6%8A%95%E7%A8%BF/tuogao39>)
中文：[中文 HTML](<https://allluckly.cn/%E6%8A%95%E7%A8%BF/tuogao39>)
English: [English HTML](<https://allluckly.cn/en/journal/2016-04-15-apple-s-xcode-testing-documentation-in-chinese-part-2/>)
发布于: 2016-04-15T00:00:00+08:00
内容更新于: 2016-04-15T00:00:00+08:00
署名：许漠颜

接续 Apple 测试文档译文，介绍代码覆盖率、命令行测试、Xcode Server 持续集成和 UI 测试录制，并讨论可测试代码的组织及从 OCUnit 迁移到 XCTest。

原文由许漠颜翻译 Apple 测试文档，Bison 编辑收录。

[原文所列来源](<http://www.jianshu.com/p/1616d9bfbb53>)

**阅读前** 这是 2015–2017 年间的技术记录，本次整理未重新运行验证示例。译文发表于 2016 年，主要处于 Xcode 7、iOS 9 与 OS X 10.11 的测试工具语境。

> "总算在今天把单元测试的官方文档翻译写成了一片博客。首先感谢党，感谢人民，感谢我的父母。也必须感谢下我们部门的领导给了我一个这样的时间来做这件事情"

编辑：[Bison](<https://allluckly.cn/>)  
 投稿：[许漠颜](<http://www.jianshu.com/p/1616d9bfbb53>)

## 代码覆盖

代码覆盖率是Xcode7的一项功能，能够显示和测量你有多少的代码执行了测试。随着你代码的覆盖你可以确定你的测试是不是达到了你预期的工作。

## 查看代码覆盖

当你的代码覆盖以后，LLVM基于方法和功能的连通的频率来收集覆盖数据。代码覆盖率不但可以收集数据也可以看测试的正确性和性能测试报告，无论是单元测试还是UI测试。 你可以查看代码覆盖通过scheme’s编辑测试行为。

1.打开scheme编辑菜单。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/1.png>)

2.选择editor scheme。

3.启用代码覆盖复选框来收集覆盖数据。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/2.png>)

4.单击close。  
 注意：代码覆盖率启用之后会在性能上有一些损失。无论损失是否显著，都影响了代码的执行，但是线性方式使性能测试仍然可以进行比较。试运行的时候启用它。你应该考虑是否启用代码覆盖率，当你对应用程序进行测试的时候。

## 如何规范代码覆盖

代码覆盖率是衡量你的测试的价值的工具。它回答了一些问题：

1.当你运行的你的测试的时候有多少代码是被运行的。  
 2.多少的测试代码才满足测试。换句话说就是，你有足够的测试框架，确保你所有的代码被检查（正确性和性能）。  
 3.哪部分代码没有被测试到。  
 测试运行以后Xcode取得LLVM得到的覆盖数据，并使用这些数据来穿件一个报表导航覆盖报告，在覆盖窗格中可以看到。它显示了测试运行的概要信息，在文件中列出了源文件和函数的列表以及，每一个的覆盖率。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/3.png>)

源代码的右侧显示了每一行代码的未执行技术。它强调了需要覆盖在没有覆盖的代码的区域。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/4.png>)

覆盖的注解绘制在右侧，显示了代码的特定部分进行了多少次的测试在测试期间的计数。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/5.png>)

有一些方法没有在测试中调用，这些方法会明显的显示在源代码编辑器中。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/6.png>)

## 自动化测试流程

在开发过程中除了以交互方式运行测试外，还可以充分采取使用Xcode Server进行自动化测试。

## 基于Server的持续集成测试

Xcode测试具有交互性，他能确保你的代码在其指定的需求下不偏离正确的轨道，并且可以简单的找到并修复BUG。一系列快速运行的功能测试不仅可以校正你的工作，还可以让你高效率的自信的构建一个健壮的程序。 这就是说，成功的开发项目往往超出单个开发人员实现和维护的能力范围。像源码管理，服务器上的自动化测试可让你顺利搞笑的根据团队的需求进行开发工作。通过Xcode Server，Xcode支持基于服务器的持续集成工作流。Xcode Server适用于OS X Server，可以自动化应用程序的构建、分析、测试以及归档的一体化过程。 下面是基于Server测试的一些优点：

1.使用服务器可以进行脱机构建和测试，以缓解开发系统做实施和调试的压力，特别是在全方位测试时可能需要很长的时间来执行。  
 2.开发团队的所有成员使用相同的scheme可在服务器上运行相同的测试，从而提高测试的一致性，整个团队也可以构建产品，就像构建测试报告。  
 3.你可以灵活调整项目需求和团队的需求。比如，当项目中任意一个成员向源代码管理系统提交新工作或者在设定的时间定期提交时测试运行就可以了。测试运行也可以按照需要手动启动。  
 4.服务器以同样的方式反复运行测试。随着时间的推移，服务器的报告可以让你和你的团队对构建过程中的问题、警告以及测试解决方案有个整体的轮廓。  
 5.你的项目可以有更多的目的进行测试，更具自动性，而且比收订运行测试系统更加经济。例如你可以有任意数量的iOS设备连接到服务器，使用单一的配置，该系统可以构建和测试库、应用程序、所有测试以及iOS模拟器的多个版本。 注意：当你的项目工作横跨iOS和Mac iOS X时，应用就会有两个约束：

1. OS X项目构建和测试时服务器必须处于运行中。
2. iOS和OS X的项目需要各自不同的scheme和bot。

## 命令行测试

使用Xcode的命令行测试，可以编写自动化脚本来构建和测试你的项目。通过使用此功能，你可以充分利用现有的构建自动化系统的优势。

1.使用XcodeBuild运行测试  
 XcodeBuild命令行工具像Xcode IDE和OS X Server中的Xcode服务一样驱动测试。使用BuildAction运行XcodeBuild测试。用-destination参数指定不同的测试目的。例如要在本地OS X“my Mac 64 Bit”测试MyApp， 使用如下命令来指定目标和框架：  
 ➢ xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination ‘platform=OS X,arch=x86\_64’ 如果你有development-enabled设备插入，你可以按照名称或者id调用它们。例如，如果你有一个名为“Development iPod touch”的iPod设备连接了测试代码，可以使用下面的命令来测试代码：  
 ➢ xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination ‘platform=iOS,name=Development iPod touch’ 测试也可以在iOS模拟器上运行。使用模拟器可以应对对不同的机型因素和操作系统版本。  
 ➢ xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination ‘platform=Simulator,name=iPhone,OS=8.1’ -destination参数可以被连接在一起，这样你只需要一个命令，就可以跨目标进行指定集成共享方案。例如下边的例子就是将上面的三个例子合在了一个命令当中：  
 ➢ \> xcodebuild test -project MyAppProject.xcodeproj -scheme MyApp -destination ‘platform=OS X,arch=x86\_64’ -destination ‘platform=iOS,name=Development iPod touch’ -destination ‘platform=Simulator,name=iPhone,OS=9.0’ 如果测试失败，XcodeBuild将返回一个非零的退出代码。  
 这些都是你所需要了解的命令行运行测试的要领。有关XcodeBuild更详细的信息，请在终端的应用程序窗口中使用命令进行查找。  
 ➢ man xcodebuild

2.在XcodeBuild中使用ssh

调用XcodeBuild从ssh远程登陆（或者demon发射）失败，除非你在主机建立一个正确的会话环境。  
 当你作为一个用户以交互方式登陆到你的OS X系统时需要创建一个“Aqua session”环境。Aqua session初始化基础框架在OS X交互环境下，为了能够运行OS X App这个是必须的。更多的特性，代码使用UI frameworks（AppKit or UIKit）也需要在“Aqua session”运行。因为这个有必要的，OS X的测试（模拟器的测试，OS X的app）都要求“Aqua session”。  
 默认的情况下，创建一个命令行使用ssh登陆到OS X系统是不能运行会话的。当你使用ssh登陆的时候你必须确保“Aqua session”被创建，你必须有一个用户登陆到了一个远端的OS X主机系统。一个用户存在运行在一个远端系统在“Aqua session”通过ssh登陆。  
 用户第一次运行在这个主机系统，运行XcodeBuild通过ssh登陆的方式进行测试。下边是通过远端的主机运行一个测试app“MyApp”通过ssh：  
 ➢\> ssh localhost ➢\> cd ~/Development/MyAppProject\_Folder ➢\> xcodebuild test -project MyApp.xcodeproj -scheme MyApp -destination ‘platform=Simulator,name=iPhone 6’ 参考：technical notes a target=”\_self” Daemons and Agents/a and a target=”\_self” Daemons and Services Programming Guide。

## 使用 Xcode Server 和 Continuous Integration

使用Xcode Server和持续集成的工作流可以设计无缝和透明的交互式开发。在使用基于服务器的持续集成过程中，很多工作都花在服务器和项目的安装配置上,在这里我们简要描述一下。在开始使用 Xcode Server 和持续集成系统时，仅需三个高级任务。此后，该任务要做的显示正在进行的监测结果和进行不定期的维护。这个概述简要地总结了这些任务，更详细的信息可在 “Xcode Continuous Integration Guide” 中查看。

## 用户界面测试

UI测试可以让你验证UI元素的属性和状态，也可以让界面间进行交互。 UI测试包括UI记录，UI测试让你有能力让你在你的App中通过一些方式进行演习，你也可以通过UI测试工具来扩展。 这个记录让UI测试得到了更多的详细信息，包含测试不通过的时候的屏幕的快照。 UI测试包括两个核心技术：XCTest framework and Accessibility。

XCTest提供框架具有UI测试的功能，和Xcode兼容。创建和使用UI测试扩展根据你会XCTest和单元测试的程度。你可以在你的工程里创建一个UI测试target、UI测试类、UI测试方法。你使用XCTest断言验证你的预期是否正确。你也可以集成一个Xcode Server和XcodeBuild。XCTest充分的兼容Object-C和Swift。 Accessibility是技术的核心，可以让残疾用户得到和一般用户一样的体验。它包含很多语义的数据用户可以通过指引使用你的App。Accessibility是UIKit和APPKit的综合有很多API允许你调整一些行为让一些功能暴露在表面进行使用。UI测试使用这些数据实现这些功能。 在源代码里创建一个UI测试类似与单元测试。你创建一个UI测试target在你的app中；Xcode默认创建一个UI测试组和实现文件，在实现文件里写了测试方法的模版。当你创建一个UI测试target，你可以指定你要测试的app。 UI测试的工作远离是找到一个应用程序的用户界面与查询对象、综合时间并派发它们到这些对象。提供了很多的API使你能够检查用户界面对象的属性和状态对他们进行比较确定是不是你期望的状态。

## 要求

UI测试不仅依赖第三方工具的服务和API也需要OS平台。你需要Xcode7，OS X 10.11 EL Capitan和iOS9。UI测试保护隐私：

iOS设备需要能够开发、连接到信任的主机。  
 OS X需要允许授权对与一些特殊的App在Xcode中。在界面测试第一次运行的时候会自动提示你。

## 概念和API

界面测试和单元测试的基本原理不同。单元测试可以让你在程序的范围能够完全的访问内部的方法、变量、状态进行一些测试。界面测试可以让你通过相同的方式使用app内部的方法、功能和变量。这使你的测试通过相同的方式揭露UI和用户遇到的问题。你的测试代码、综合时间、用户界面作为一个单独的用用程序运行。

## APIs

XCUIApplication。 XCUIElement。 XCUIElementQuery。

## 开始使用UI记录

开始使用UI记录。他产生的源代码转换成可以被编辑来构建测试或回放一个也定场景的测试的实现文件。UI记录也是非常有用的对于探索新的用户界面或学习如何编写UI测试。操作的基本顺序如下：

使用测试导航面板，创建UI测试target。 在所创建的文件中，将光标移动到测试功能。 启动UI记录。 该程序启动和运行。行使程序做UI操作的序列。Xcode捕捉函数体的行动纳入数据。 当你要测试的动作完成以后，停止录制UI。 添加XCTest断言数据。

## 编写UI测试

API测试可以同时进行功能测试和性能测试，所以可以进行UI测试。UI测试在应用程序的界面进行操作，很多简单的功能都集成到界面测试里测试是不是预期的表现和反应。 UI测试从事件的响应级别进行操作：

1.查找到一个元素。  
 2.知道一个元素的预期行为。  
 3.点击或点击该元素引起反应。  
 4衡量是不是响应了预期的行为。

创建一个UI测试通过XCTest创建和单元测试一样的编程模型。类似的操作和编程方法的整体使用，给出UI测试的API基本概念，以及它们如何运作。在测试类结构提供setup方法，和单元测试类不相同。

```
- (void)setUp {
    [super setUp];
    // Put setup code here. This method iscalled before the invocation of each test method in the class.
    self.continueAfterFailure = NO;
    [[[XCUIApplication alloc] init] launch];
}
```

Self.continueAfterFailure值默认值设置为NO。一个正确的UI测试依赖于前一个测试的成功。如果一个测试失败，下边的所有测试失败就因为最前边的测试失败。 另外setup方法包括创建实例XCUIApplication并启动它。UI测试必须启动它来进行测试，并缺都在setup方法的测试方法之前运行，这确保了应用启用下边的测试。 编写UI测试方法的时候你应该使用UI录制功能创建一个测试的步骤。你的目的就是编辑这个基本的序列，使用XCTest断言确定是不是一个成功或者失败的单元测试。UI测试可以同时测试功能和性能就像单元测试一样。 保证一个正确的UI测试一般模式如下：

1.使用XCUIElementQuery找到下一个XCUIElement。  
 2.合成一个事件并将其发送到XCUIElement。  
 3.使用断言的XCUIElement的状态比较预期的参考状态。

## 附录A：编写可测试的代码

Xcode集成了对测试的支持，使您能够构建测试包，以支持各种不同方式的开发工作。使用测试，可以发现代码中潜在的回归，并测试预期的成功与否，并验证应用程序的行为。通过确保对象能以预期的方式运行，测试能提高代码的稳定性。 当然，通过测试让程序达到稳定的水平也取决于你写的测试的质量。同样，编写良好测试的难易度也取决于你的编码方式。专为测试设计的代码编写有助于编写良好的测试。阅读下面的指南，以确保你的代码是可测试的，以有效减小编写良好测试的难度。

## 指南

1.定义API的需求。  
 为添加到项目中的每个方法或者函数定义,需求和结构都非常重要。对于需求，包括输入和输出范围，exception抛出异常、条件限制以及返回值的类型（尤其如果值是实例的时候）。定义要求并确保满足代码中的需求可以帮助你编写出健壮的安全的代码。  
 2.边写边侧  
 每当你设计和编写出一个方法或函数时，就应该编写一个或多个测试用例来确保API的需求得到满足。记住，为现有代码编写测试要比你为正在编写的代码难得多。  
 3.检查边界条件  
 如果对一个方法的参数值必须在特定的范围内，你的测试应包括该范围的最低和最高值。例如如果一个程序有一个整数参数，那么该参数值的范围要在0和100之间（包括首尾值），该方法的测试代码应该为参数传递0，50和100这些值。  
 4.使用negative测试  
 negative测试可以确保你的代码能够适当地响应出错的条件。当收到无效的或意外的输入值时，它可以验证代码的行为。同样的，还可以验证它返回错误代码或者引发异常的行为。例如，如果一个证书参数范围必须为1？100（包含首尾值），创建测试用例并传值－1和101，以确保该程序能够引发出一个异常或者返回一个错误代码。  
 5.编写全面的测试用例。  
 全面的测试通过结合不同的代码模块来实现API的一些更复杂的行为。虽然简单，隔离测试提供值，堆叠测试表现复杂行为，这样能捕获更多的问题。这些类型的测试在更现实的条件下模拟你的代码的行为。例如除了将对象添加到数组，你还可以创建数组为之添加几个对象，使用不同的方法删除若干对象，然后确保集合以及其余对象的数量是正确的。  
 6.使用测试用例覆盖BUG修复  
 每当你修复完一个BUG，都要编写一个或者多个测试用例，来验证此次修复的有效性。

## 附录B：从OCUnit过度到XCTest

XCTest是Xcode5中新引入的一个测试框架。XCTest是上一代测试框架OCUnit的更现代化的实现。XCTest提供了与Xcode更好的集成并且奠定了未来改进Xcode测试能力的基础。XCTest的许多功能都类似与之前的OCUnit。

## OCUnit和XCTest兼容性

自从Xcode2.1以来，OCUnit都是Xcode测试的基础，所以很多现有的项目都是基于OCUnit测试。它们可以继续使用，因为Xcode5为基于OCUnit和XCTest的两种项目提供了等同的功能。 将基于 OCUnit 测试的现有项目从 Xcode 5 之前的版本添加进 Xcode 5中时，项目会兼容当前 iOS 和 OS X 版本，同样的，iOS 7之前的版本以及 OS X v10.8 之前的版本也是如此。 基于 OCUnit 的测试可以在 iOS 6 和 iOS 7 上运行，所以针对iOS 和 OS X 旧版本的项目仍然能有效地选择使用 OCUnit。当你需要把项目从 Xcode 5 回归至早期版本的Xcode，并对应用程序进行维护时，这也不失为一个很好的选择。  
 如果你的项目开发工作主要集中于 iOS 7 或更高版本，或在 OS X v10.8 或更高版本，或两者兼而有之，把项目转为使用 XCTest 将是一个正确的选择。  
 注意：OCUnit在Xcode5.1中被标记为已过时。

## 从OCUnit过渡至XCTest

从 OCUnit 到 XCTest 的转换是一个复杂的操作，包括更新源文件，其中包括测试类和修改项目配置设置。Xcode5 中有一个转换工作流程的助手可帮你实现这些转换，选择 Edit \> Refactor \> Convert OCUnit to XCTest。使用该工具来成功地将项目迁移使用 XCTest。  
 OCUnit 到 XCTest 转换工具是基于target-by-target的。该工具会检查你选择的目标，并且在执行自动转换后让你知道它们是否可以用XCTest运行。  
 注意：建议你进行OCUnit到XCTest迁移时，将所有的target放到一个项目中。  
 把项目从OCUnit更新到XCTest：

1.工具tabbar上选择编辑菜单。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/7.png>)

在出现的菜单中选择一个方案。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/8.png>)

2.选择Edit \> Convert \> To XCTest。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/9.png>)

3.点击下一步，进入到下一个工作表。  
 4.在出现的工作表中选择测试target

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/10.png>)

一个特定的目标将建立XCTest转换后,单击其名称。  
 5.单击下一步按钮。弹出一个FileMerge界面，你可以通过文件对比评估源码的更改。

![1](<https://allluckly.cn/images/blog/tuogao/tougao39/11.png>)

左边是更新后的源文件，右边是原始文件。你可以浏览所有可能的变化，并丢弃那些你觉得有问题的代码。 6.如果你对所有的更改都满意，就可以单击保存按钮。Xcode会把更改写入文件。

## 手动的从OCUnit转换到XCTest

如果一些项目中OCUnit不能自动的转换到XCTest，你就需要手动的去转换，步骤如下：

1.添加一个新的XCTest测试target在这个项目中。  
 2.在你的测试文件中增加测试类和测试方法。  
 3.编辑你的测试类引入#import XCTest/XCTest.h在你的方法里使用断言。  
 使用这种方法可以确保项目设置是正确配置XCTest target。

---

好文推荐：[iOS开发之AES+Base64数据混合加密与解密](<https://allluckly.cn/aes/AES>)

