代码质量和应用分发
449
创建
DocumentViewController
时会立即创建
AVSpeechSynthesizer
。然而,严格来
说无需立即创建
AVSpeechSynthesizer
,可以等到用户想朗读文本时再创建。
这个问题最好的解决方法是把
AVSpeechSynthesizer
存储为惰性存储属性
lazy
stored property
。惰性属性的作用与其他属性类似,只不过它不会立即初始化,而
是等到首次访问时才初始化。如果把
speechSynthesizer
改成惰性属性,那么加载
DocumentViewController
的时间就会减少。
5.
打开
DocumentViewController.swift
,把下面这行代码:
let speechSynthesizer = AVSpeechSynthesizer()
改成:
lazy var speechSynthesizer = AVSpeechSynthesizer()
搞定!再次执行前述步骤:重新启动应用,转到
Instruments
中,然后打开一个文档。加
载文档的时间应该会减少。
评估应用所做的事情,找出需要修改的地方,然后优化。这个过程可以做很多次,而且
以不同的方式做。这一节只说明了如何减少
CPU
时间。不过,你可以使用相同的原理
减少内存消耗量、数据读写量和网络数据传输量。
17.3
测试
简单的应用易于测试,但是复杂的应用很难正确测试。人们喜欢先添加一些代码,然后
检查是否可行。可是,添加的代码量越多,某部分代码破坏其他部分的几率就越大。为
了确保应用可以正常运行,我们要测试整个应用。然而,测试会带来许多问题:
繁琐乏味,从而抗拒全面测试。
需要不断重复,因此可能使用相同的方式测试不同的功能,而且容易疏漏。
某些问题仅当以特定的方式使用应用时才会出现。使用场景越精细,测试的动力越低。
为了解决这些问题,现代的软件开发大量使用自动化测试。自动化测试每次都以相同的
方式运行相同的测试,检查整个过程的每一步,因此能立即解决上述问题。此外,自动
化测试能大大降低精神负担。
Xcode
支持两种自动化测试:单元测试和用户界面测试。
450
17
17.3.1
单元测试
单元测试是隔离的小型独立测试,用于确认代码中特定部分的行为。单元测试特别
适合确认方法的输出是否与预期相符。例如,我们在第
6
章编写的从
JSON
中加载位
置的代码就很容易测试:给定包含
lat
lon
的有效
JSON
,我们期望能创建一个
CLLocationCoordinates
对象此外,如果给定无效的
JSON
,或
JSON
中没有那两个值,
我们期望得不到坐标。这一点同样重要。
单元测试放在单元测试包中。新建项目时可以选择包含单元测试;现有项目可以自己添
加,方法是:打开“
File
”菜单,选择“
New
”→“
Target
”,然后选择“
Tests
”区域中
的“
Unit Tests
”(见图
17-10
)。
17-10
在项目中添加单元测试包
测试包中包含一到多个测试用例;测试用例是
XCTestCase
的子类,其中包含各个单元测
试。下面是一个测试用例:
func testDocumentTypeDetection() {
//
使用空数据创建一个
NSFileWrapper
let data = NSData()
代码质量和应用分发
451
let document = NSFileWrapper(regularFileWithContents: data)
//
给它起个名字
document.preferredFilename = "Hello.jpg"
//
现在它应该认为自己是图像
XCTAssertTrue(document.conformsToType(kUTTypeImage))
}
XCTestCase
类中的测试是方法。
Xcode
运行测试时(稍后说明)首先找出
XCTestCase
的全部子类,再找出各个子类中以
test
开头的全部方法,然后运行测试。测试用例的
setUp
方法先运行,然后是测试本身,最后是测试用例的
tearDown
方法。
注意上述代码中使用的
XCTAssertTrue
函数。这是众多
XCTAssert
函数中的一个,用
于测试特定的条件。如果它失败,整个测试就失败
Xcode
会继续运行下一个测试
XCTAssert
函数的完整列表参见
Xcode
测试文档(
http://apple.co/22VaRyg
)。
如果想运行当前目标中的单元测试,按
-U
键,或者单击某个测试第一行左边的图标,
如图
17-11
所示。
17-11
运行某个测试
Xcode
会启动应用,运行测试,然后报告哪个测试失败了(如果有的话)。
17.3.2 UI
测试
为了全面了解应用的运行情况,只使用单元测试还不够。隔离测试部分代码虽然作用巨
大,但是这不足以让我们相信有多个组件交互的整个应用能正常运行。例如,若想使用
单元测试对“创建、编辑和保存文档”这个过程做测试,可不是件容易的事。
我们可以使用
UI
测试确认应用的行为与使用的方式是否一致。
UI
测试就是记录用户
与界面的交互过程,只不过记录的方式要智能得多。记录
UI
测试时,
Xcode
会注意你
执行的每个交互,然后为其生成一行代码。
记录
UI
测试得到的代码如下所示(注释是我们添加的,用于说明各个步骤):
func testCreatingSavingAndClosingDocument() {
452
17
//
获取应用
let app = XCUIApplication()
//
选择
File->New
菜单
let menuBarsQuery = XCUIApplication().menuBars
menuBarsQuery.menuBarItems["File"].click()
menuBarsQuery.menuItems["New"].click()
//
获取新建的未命名窗口
let untitledWindow = app.windows["Untitled"]
//
获取主文本视图
let textView = untitledWindow.childrenMatchingType(.ScrollView)
.elementBoundByIndex(0).childrenMatchingType(.TextView).element
//
输入一些文本
textView.typeText("This is a useful document that I'm testing.")
//
Command-S
键保存
textView.typeKey("s", modifierFlags:.Command)
//
出现保存附着对话框
//
输入“
Test
”,然后按回车键
untitledWindow.sheets["save"].childrenMatchingType(.TextField)
.elementBoundByIndex(0).typeText("Test\r")
//
关闭文档
app.windows["Test"].typeKey("w", modifierFlags:.Command)
}
UI
测试运行的方式与单元测试一样。运行测试时,系统会接管电脑的控制权,按照测
试中的步骤逐一执行。因此,每次运行测试都会以完全相同的方式测试应用。
此外,还可以直接在
UI
测试中记录你与应用的交互。这样特别方便,不用学习涉
及的
API
,你只需像往常那样使用应用,
Xcode
会注意你做了什么。更多信息参见
Xcode
文档中的“
Writing Tests
”(
http://apple.co/22VbeJ1
)。
构建机器人
构建机器人是运行在服务器中的一个程序,它监视着源码的变化,然后自动构建、
测试和打包软件。构建机器人能减轻主力开发电脑的负担,还能确保始终运行测试。
若想创建构建机器人,首先要有一台运行
Apple OS X Server
系统(可以在
App
Store
中购买)的
Mac
。关于构建机器人的更多信息参阅
Xcode Server and
Continuous Integration Guide
”(
http://apple.co/22VblV3
)。

Get Swift学习手册 now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.