持续集成系列 - 测试: XCTest

测试简述

自动执行测试,自动构建并分发,自动部署到 ITC

自动化测试 –> 持续部署

在互联网的产品开发时代,产品迭代越来越频繁,“从功能开发完成直到成功部署”这一阶段被称为软件开发“最后一公里”。很多开发团队也越来越认识到,自动化测试和持续部署可帮助开发团队提高迭代效率和质量。 那么,如何更好地解决“最后一公里”这一问题呢?

一切从自动化测试开始,让自动化测试贯穿在整个项目开发-集成-部署-交付的-开发流程中。

在这个分层自动化测试金字塔中,

Unit 代表单元测试:

XCTest是苹果在iOS 7和Xcode5引入的一个简单而强大的测试框架,它的测试编写起来非常简单,并且遵循xUnit风格。XCTest的优点是与Xcode深度集成,有专门的Test导航栏,但因为受限于官方测试API,因此功能不是很丰富。

iOS 中的单元测试开源库:

  • Kiwi是对XCTest的一个完整替代,使用xSpec风格编写测试。Kiwi带有自己的一套工具集,包括expectations、mocks、stubs,甚至还支持异步测试。
  • Specta与Kiwi功能相似,但在架构上非常不同。Kiwi注重功能的整合,而Specta则注重模块化。它本身只专注于运行测试,而将模拟、匹配等功能交给第三方。下 下面这些一些开源测试组件,它们能与Specta和Kiwi框架搭配使用:
  • Expecta:匹配程序框架。
  • OCHamcrest:匹配程序框架。
  • OCMock:模拟测试框架。
  • OCMockito:模拟测试框架。
  • OHTTPStubs:模拟网络请求的库,基于block的语法来匹配URL。
  • Nocilla:模拟网络请求的库,使用链式API。
  • Quick是:一个使用Swift开发的新测试框架,对测试使用Swift编写的App非常友好。它还有一个Nimble库用于编写匹配模式。

UI自动化测试框架

一些第三方自动化测试框架则比较成熟,如Appium, MonkeyTalk,Frank等,这里介绍KIF和EarlGrey:开源\内嵌式框架 (以 framework 形式内嵌至应用中) , 本质上是iOS的Unit test \使用Object-C和Swift\支持真机和模拟器

  • EarlGrey:原生的 iOS UI 自动化测试框架,写法多样,操作灵活,作为后来者的EarlGrey功能更加强大.github/文档
  • KIF:出来早\KIF的语法比较简单\适合快速开发.github文档

iOS 自动化测试实践

###单元测试(Unit Testing)是针对程序单元进行正确性检验的测试工作,程序单元是应用的 最小可测试部件.

  • Expecta:专为Objective-C/Cocoa而生,相比OCHamcrest,其优化了匹配的语法,测试用例的可读性更高。
  • OCHamcrest:
  • GHUnit已被弃用,不能积极维护!使用XCTest来代替。
  • OCUnit,被官方集成进XCode 4.x版本中;

持续集成CI(Continuous Integration)是一种实践,可以让团队在持续的基础上收到反馈并进行改进,不必等到开发周期后期才寻找和修复缺陷.通俗一点儿说:就是指对于开发人员的每一次代码提交,都自动地把Repository中所有代码Check out到一个空目录,并且自动运行所有Test Case.如果成功则接受这次提交,否则告诉所有人,这是一个失败的Revision[2]

说起 UI 测试,在 iOS 的开源社区有过一系列的尝试,比如 KIF 框架,Apple 自己的 Automating UI Testing 或者 Facebook 的截图测试等.这些方法有一个共同的特点,那就是配置起来十分繁琐,使用上也有诸多不便.这大概也是 UI 测试所面临的最大窘境 – 往往开发者在一个项目里写了一两个 UI 测试用例后,就会觉得难以维护,怯于巨大的时间成本,继而放弃.

Apple 在 Xcode 7 中新加入了一套 UI Testing 的工具,其目的就是解决这个问题.新的 UI Testing 比以往的解决方案要简单不少,特别是在创建测试用例的时候更集成了录制的功能,这有希望让 UI Testing 变得更为普及.

其他概念比如: 单元测试\集成测试.

单元测试:对软件中的最小可测试单元进行检验。通常而言,一个单元测试是用于判断某个特定条件(或者场景)下某个特定函数的行为。相比其他层级的测试,单元测试发现并解决问题付出的成本相对来说最低,而投入产出比最高

集成测试:是在单元测试的基础上,将所有模块按照设计要求(如根据结构图)组装成为子系统或系统,进行集成测试集成测试是在单元测试的基础上,测试在将所有的软件单元按照概要设计规格说明的要求组装成模块、子系统或系统的过程中各部分工作是否达到或实现相应技术指标及要求的活动。也就是说,在集成测试之前,单元测试应该已经完成。这一点很重要,因为如果不经过单元测试,那么集成测试的效果将会受到很大影响,并且会大幅增加软件单元代码纠错的代价。

UI Testing 和 Accessibility

在 iOS 中使用 XCTest, 就必须要了解 Accessibility. UI Accessibility 早在 iOS 3.0 就被引入了,用来辅助身体不便的人士使用 app.VoiceOver 是 Apple 的屏幕阅读技术,而 UI Accessibility 的基本原则就是对屏幕上的 UI 元素进行分类和标记.两者配合,通过阅读或者聆听这些元素,用户就可以在不接触屏幕的情况下通过声音来使用 app.

Accessibility 的核心思想是对 UI 元素进行分类和标记 – 将屏幕上的 UI 分类为像是按钮,文本框,cell 或者是静态文本 (也就是 label) 这样的类型,然后使用 identifier 来区分不同的 UI 元素.用户可以通过语音控制 app 的按钮点击,或是询问某个 label 的内容等等,十分方便.iOS SDK 中的控件都实现了默认的 Accessibility 支持,而我们如果使用自定义的控件的话,则需要自行使用 Accessibility 的 API 来进行添加.

UI 测试的本质就是定位在屏幕上的元素,实现一些像是点击或者拖动这样的操作交互,然后获取 UI 的状态进行断言来判断是否符合我们的预期.这个过程及其需求与 Accessibility 的功能是高度吻合的.这也是为什么 iOS 中大部分的 UI 测试框架都是基于 UI Accessibility 的原因, UI Testing 也不例外.

demo

demo 比较简单,主要用于演示基本的流程,代码在 GitHub 中.

相比起其他一些 UI 测试框架,Xcode 的 UI Testing 最为诱人的优点在于可以直接录制操作.新建一个 XCTest,默认实现如下:

import XCTest

class UITESTUITests: XCTestCase {
        
    override func setUp() {
        super.setUp()
        
        continueAfterFailure = false
        
        // launch 方法来启动测试 app
        // XCUIApplication 是 UIApplication 在测试进程中的代理 (proxy)

        XCUIApplication().launch() 

    }
    
    override func tearDown() {
        super.tearDown()
    }
    
    func testExample() {
        
    }
    
}

使用的方法是,先创建一个测试方法,然后将光标停留在方法中,然后点击录制.和 app 的交互就会被自动转写成代码.

操作是:

  • 2次点击 “color” 按钮 ,改变背景色
  • 点击”下一页”按钮 push 到第二页
  • 点击”back” 按钮 pop 回第一页

func testMyApp() {
        
        let app = XCUIApplication()

        // "color" 按钮设置 Accessibility id 为 changeColor
        let changecolorButton = app.buttons["changeColor"]

        changecolorButton.tap()
        changecolorButton.tap()

        // "下一页"按钮没有设置 Accessibility id
        app.buttons["下一页"].tap()

        // "back" 按钮设置 Accessibility id 为 back
        app.buttons["back"].tap()
        
    }

编写完成之后可以 cmd+U 运行试试吧.

参考及延伸阅读

支持一下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码支持
扫码支持一下

打开支付宝扫一扫,即可进行扫码打赏哦