iOS 单元测试和UI测试教程

发表于:2017-7-14 15:29

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:颐和园    来源:博客

  编写测试不是为了追求刺激,测试是为了避免你崭新的 App 变成了充满 bug 的垃圾,它是必须的。如果你正在阅读本教程,说明你已经意识到为你的代码和 UI 编写测试的重要性了,但你不一定知道怎么在 Xcode 中进行测试。
  也许你已经有一个“功能正常”的 App 了,但根本没有为它进行过测试,你想在扩展它时能够测试这些修改。可能你也写过一些测试,但不知道这些测试是否正确。又或者,你正在编写 App,但想随时测试它。
  本教程演示如何使用 Xcode 的测试导航器来测试 App 的模型或者异步方法,用 stubs 和 mocks 来模拟与框架或系统对象进行交互,如何测试 UI 及性能,以及如何使用代码覆盖工具。然后,你会学到测试狂人口中的一些词汇,在教程最后,你会充满自信地面对 SUT(被测系统)~
  测试,测试……
  什么是测试?
  在编写测试之前,首先需要知道:你应该测试什么?如果你的目标是修改一个已有的 App,你首先应该对准备修改的组件编写测试。
  通常,测试应当包含:
  核心功能:模型类和方法,以及它们和控制器的交互
  最常用的 UI 操作
  边际条件
  bug 修复
  重要的事情说三遍 —— FIRST 原则:测试的最佳实践
  FIRST 是几个单词的缩写,简要描述了有效的单元测试需要什么条件,这些条件包括:
  Fast:测试的运行速度要快,这样人们就不介意你运行它们了。
  Independent/Isolated:一个测试不应当依赖于另一个测试。
  Repeatable:同一个测试,每次都应当获得相同的结果。外部数据提供者和并发问题会导致间歇性的出错。
  Self-validating:测试应当是完全自动化的,输出结果要么是 pass 要么是 fail,而不是依靠程序员对日志文件的解释。
  Timely:理想情况下,测试的编写,应当在编写要测试的产品代码之前。
  遵循 FIRST 原则会让你的测试清晰和有用,而不会成为 App 的渊薮。
  开始
  下载、解压缩和打开这个开始项目 BullsEye 和 HalfTunes。
  BullsEye 是 iOS Apprentice 中的一个示例 App,我将游戏逻辑抽离到了一个 BullsEyeGame 类中,然后曾加了允许改变游戏风格的功能。
  在右下角有一个 segmented 控件,允许玩家选择游戏风格:Slide,拖动 slider 能够尽可能地接近目标值,或者 Type,用猜的方式计算 slider 的位置。这个控件的 action 方法会保存用户选择的游戏风格到 user defaults 中。
  HalfTunes 是 NSURLSession 教程 中的示例 App,已升级到 Swift 3。用户可以通过 iTunes API 搜索歌曲,下载和播放歌曲的片段。
  开始测试吧!
  用 Xcode 进行单元测试
  创建一个单元测试 Target
  Xcode 的测试导航器提供了一种最简单的进行测试的方法;你可以用它创建一个测试 target 并在你的 app 中进行测试。
  打开 BullsEye 项目,按下 command+5 打开它的测试导航器。
  点击左下角的 + 按钮,然后从菜单中选择 New Unit Test Target…:

  使用默认的 BullsEyeTests 作为名字。当导航器中显示出测试 bundle 时,点击并在编辑器中打开它。如果 BullsEyeTests 没有自动显示,点击其它导航器,然后返回测试导航器。

  模板代码中,import 了 XCTest,并定义了一个 XCTestCase 的继承类 BullsEyeTests,并声明了 setup()、tearDown() 和 示例测试方法。
  有三种运行这个测试类的方法:
  1、Product\Test 或者 Command-U。这实际上会运行所有测试类。
  2、点击测试导航器中的箭头按钮。
  3、点击中缝上的钻石图标。

  你还可以点击某个测试方法上的钻石按钮单独测试这个方法,钻石按钮在导航器和中缝上都有。
  测试不同的运行测试方法,看看它们会运行多长时间,以及运行起来的样子。示例测试不会执行任何动作,因此它们的运行是十分快速的!
  如果所有测试通过,钻石会变绿并显示一个对勾。点击 testPerformanceExample() 底部的灰色钻石,打开 Performance Result:

  你用不着 testPerformanceExample() 方法,请删除它。
  用 XCTAssert 测试模型
  首先,用 XCTAssert 测试 BullsEye 的模型中的一个核心功能:一个 BullsEyeGame 对象能够正确计算出一局游戏的得分吗?
  在 BullsEyeTests.swift 中,在 import 语句下面添加:
  @testable import BullsEye
  这样单元测试就可以访问 BullsEye 中的类和方法了。
  在 BullsEyeTests 类头部加入一个属性:
  var gameUnderTest: BullsEyeGame!
  在 setup() 方法中创建一个新的 BullsEyeGame 对象,位于 super 方法调用之后:
  gameUnderTest = BullsEyeGame()
  gameUnderTest.startNewGame()
  这会用类的级别创建出一个 SUT(被测系统)对象,因此这个测试类中的所有测试都能够访问 SUT 对象的属性和方法。
  这里,你也调用了游戏的 startNewGame 方法,这会创建一个 targetValue。你会有很多测试都要使用 targetValue,以测试游戏中计算的得分是否正确。
  别忘了在 tearDown() 方法中释放你的 SUT 对象,在调用 super 方法之前:
  gameUnderTest = nil
  注意:在 setup() 中创建 SUT,在 tearDown() 中释放 SUT 是一种好的做法,能够保证每次测试都以干净的状态开始。更多讨论,请阅读 Jon Reid 的这篇帖子。
  准备编写你的第一个测试了!
  将 testExample() 方法修改为:
  // 用 XCTAssert 测试模型
  func testScoreIsComputed() {
    // 1. given
    let guess = gameUnderTest.targetValue + 5
    // 2. when
    _ = gameUnderTest.check(guess: guess)
    // 3. then
    XCTAssertEqual(gameUnderTest.scoreRound, 95, "Score computed from guess is wrong")
  }
  测试方法的名字总是以 test 开头,后面加上一个对测试内容的描述。
  将测试方法分成 given、when 和 then 三个部分是一种好的做法:
  在 given 节,应该给出要计算的值:在这里,我们给出了一个猜测数,你可以指定它和 targetValue 相差多少。
  在 when 节,执行要测试的代码,调用 gameUnderTest.check(_:)方法。
  在 then 节,将结果和你期望的值进行断言(这里,gameUnderTest.scoreRound 应该是 100-5),如果测试失败,打印指定的消息。
  点击中缝上或者测试导航器上的钻石图标。App 会编译并运行,钻石图标会变成绿色的对勾!
  注意:要查看完整 XCTestAssertions 列表,Command+左键,点击 XCTAssertEqual,将跳到 XCTestAssertions.h,或者通过阅读苹果的 Assertions Listed by Category。

  注意:Given-When-Then 结构源自 BDD(行为驱动开发),是一个对客户端友好的、更少专业术语的叫法。另外也可以叫做 Arrange-Act-Assert 和 Assemble-Activate-Assert。

21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号