iOS KIF自动化测试

一. iOS单元测试,UI测试基本介绍
二. KIF简介
三. KIF集成
四. 测试用例编写
五. jenkins集成步骤
六. 总结
一 iOS单元测试,UI测试基本介绍
1.1 简单介绍

iOS有两个层次的测试:单元测试,UI测试。
单元测试:XCTest,XCTest最后生成的是一个bundle。bundle是不能直接执行的,必须依赖于一个宿主进程。XCTest主要基础功能:异步测试,性能测试,代码覆盖率等。
UI测试:UI Testing,UI测试是模拟用户操作,进而从业务处层面测试,iOS UI测试还有一个核心功能是UI Recording。选中一个UI测试用例,然后点击图中的小红点既可以开始UI Recoding,录制完成之后,会自动生成一段测试代码。

1.2 项目中如何集成

如果是一个新项目,在创建项目的时候,直接勾选 include Unit Tests,和include UI Tests 即可,如下图:


iOS 新项目如何加入单元测试和UI测试.png
1.2 已有项目中如何集成

如果我们有一个已有项目,可能前期没有加入测试框架,那么后期我们如何引入呢,步骤如下图:

步骤一 :点击项目工程,在配置文件右下角点击+号会弹出一个选择框

步骤一

步骤二 :下滑到test一栏,这里就找到了单元测试和UI测试,这里我们选择iOS UnitTesing Bundle

步骤二

步骤三 :填写一些基本信息,
步骤三

步骤四 :添加成功的页面,Testable SwiftTests目录就是就是我们刚生成的,今后的测试用例也都是在这个目录下面写。
步骤四

总结:这里只是简单的介绍iOS测试方面的一些东西,我们今天的主要目的是讲一个第三方的UI测试框架,以及如何结合jenkins做自动化测试,所以这里就不详细介绍了,下面开始介绍我们的主题。

二. KIF简介

2.1 简要说明
KIF代表Keep It Functional,是一款iOS集成测试框架。 通过利用操作系统为具有视觉障碍的用户提供的辅助功能属性,可以轻松实现iOS应用程序的自动化。

KIF使用标准的XCTest测试目标来构建和执行测试。 测试在主线程中同步进行(运行运行循环以强制时间流逝),从而允许更复杂的逻辑和组合。 这也使得KIF能够利用Xcode Test Navigator,命令行构建工具和Bot测试报告。

KIF使用未公开的Apple API。 大多数iOS测试框架都是如此,并且对于测试目的而言是安全的,但重要的是KIF不会将其转换为生产代码,因为它会让您的应用程序提交被Apple拒绝。 按照下面的说明确保KIF为您的项目配置正确。

KIF是基于XCTest的一个第三方UI测试框架,XCTest是iOS的单元测试框架,所以项目中加入XCTest框架可以做单元测试,又通过引入KIF框架做UI集成测试。

2.2 功能特性
1 最小化间接性
所有的KIF测试都是用Objective-C编写的。 这可以最大程度地集成代码,同时最大限度地减少必须构建的图层数量。

2 简单的配置
KIF直接集成到您的Xcode项目中,因此无需运行其他Web服务器或安装任何其他软件包。

3 宽操作系统和Xcode覆盖
KIF的测试套件正在针对iOS 8+和Xcode 7+运行。 较低的版本可能仍然有效,但你的里程可能会有所不同。 我们尽最大努力保留向后兼容性。

4 像用户一样测试
KIF试图模仿实际的用户输入。 尽可能使用触摸事件来完成自动化。

5 与Xcode测试工具自动集成
您可以使用测试导航器轻松运行单个KIF测试,或者使用机器人启动每晚验收测试。

三. KIF集成

我们通过cocopod来进行引入
步骤一
项目中要先引入XCTest,引入步骤和方法,可以参考本文上面(1.2 已有项目中如何集成 )章节

步骤二
打开工程里的Podfile文件加入以下代码:

target 'MyApp' do
    pod 'Alamofire'
    pod 'SwiftProgressHUD'
    pod 'WechatOpenSDK'
    pod 'Bugly'
end
target 'MyAppTests' do
     pod 'KIF'
end

这里要注意target是项目的Tests,不要加错位置了,当初我就加错了加到target "MyApp",然后在写测试用例是引入KIF.h,总是报错,可能当时没太注意这个细节,结果掉坑里了。编辑完成,pod install 一下。

步骤三

1: 项目名Tests对象 (项目名+Tests)---> Build Phase ---> Target Dependencies ---> "+" --->"项目的Tests文件"(去百度一下这个 tests 文件 和UItests 文件有什么区别)

2: 项目名Tests对象 ---> Build Settings ---> Linking(直接搜)---> Bundle Loader 填写"$(BUILT_PRODUCTS_DIR)/项目名称.app/项目名称"

3: 项目名Tests对象 ---> Build Settings ---> Wrapper Extension (直接搜)设置成 "xctest"

4: 点击你 RUN 按钮前面的前面的项目target ---> Edit Scheme... ---> Test 看看里面有没有你要测试的项目,没有就添加

步骤四
在Tests目录下创建一个桥接文件(创建桥接文件,可以在当前目录下新建一个oc文件,xcode中途会提示是否创建桥接文件,桥接文件创建完成后,再把oc文件删除就行了),KIF是OC写的,用swift写测试用例就要创建一个桥接文件,oc的话就不用了。

步骤四

总结:自此,KIF我们就已经集成完毕了,下面就开始我们测试用例的编写了。

四. 测试用例编写

我们写了一个登陆流程的示例:新建一个LoginTest.swift文件有几个注意点:
1 要导入KIF头文件 import KIF
2 底层没有提供tester方法,所以要加一个扩展
3 类要继承 KIFTestCase类
4 tester().usingLabel("login_phone"),使用usingLabel获取控件,前提是项目中这个控件的要设置accessibilityLabel 属性

image.png

LoginTests.swift

import XCTest
import KIF

extension XCTestCase {
    func tester(_ file : String = #file, _ line : Int = #line) -> KIFUIViewTestActor {
        return KIFUIViewTestActor(inFile: file, atLine: line, delegate: self)
    }
    
    func system(_ file : String = #file, _ line : Int = #line) -> KIFSystemTestActor {
        return KIFSystemTestActor(inFile: file, atLine: line, delegate: self)
    }
}
class LoginTests: KIFTestCase {

    func testLogin(){
        noInputLogin()
        noValidateLogin()
        validateLogin()
        agreeValidateLogin()
    }
    
    func testAdd() {
        let a = 3
        let b = 4
        XCTAssert(a+b == 7, "计算正确")
    }
    func testnoValidateLogin(){
        
        let userNameInput = tester().usingLabel("login_phone")
        userNameInput?.enterText("15856885688")
        let loginBtn =  tester().usingLabel("登录")
        loginBtn?.tap()
        tester().wait(forTimeInterval: 2)
    }
    
    func noInputLogin(){
        let loginBtn =  tester().usingLabel("登录")
        loginBtn?.tap()
        tester().wait(forTimeInterval: 2)
    }
    
    func noValidateLogin(){
        
        let userNameInput = tester().usingLabel("login_phone")
        userNameInput?.enterText("15856885688")
        let loginBtn =  tester().usingLabel("登录")
        loginBtn?.tap()
        tester().wait(forTimeInterval: 2)
        
    }
    
    func validateLogin(){
        let invalicaodeInput = tester().usingLabel("login_input_invlicode")
        invalicaodeInput?.enterText("123456")
        let valicodeBtn = tester().usingLabel("获取验证码")
        valicodeBtn?.tap()
        let loginBtn =  tester().usingLabel("登录")
        loginBtn?.tap()
        tester().wait(forTimeInterval: 2)
    }
    
    func agreeValidateLogin(){
        
        let login_agree = tester().usingLabel("login_agree")
        login_agree?.tap()
        let loginBtn =  tester().usingLabel("登录")
        loginBtn?.tap()
        let firstPage = tester().usingLabel("首页").waitForView()
        if  (firstPage != nil) {
            loginOut()
        } else {
            XCTAssert(false, "未找到页面")
        }
    }
    
    func loginOut(){
        let meBtn = tester().usingLabel("我")
        meBtn?.tap()
        
        let setUpBtn = tester().usingLabel("设置")
        setUpBtn?.tap()
        
        let outBtn = tester().usingLabel("退出登录")
        outBtn?.tap()
        
        tester().wait(forTimeInterval: 5)
    }
}

所有的测试方法要以test头,不以test开头的方法,测试是不会执行的,但可以作为内置方法,其他的测试方法可以调用。这里只做一个示例具体使用请参考官方文档:https://github.com/kif-framework/KIF,官方demo它提供了如下一些操作示例:

官方demo示例,列表操作,滑动操作,文本,选择框,刷新,长按等等

到此KIF集成,使用流程,我们基本介绍完了。下面我们看下如何结合jenkins做自动化测试

五. jenkins集成步骤

步骤一
首先我们要把已经完成的测试用例的项目上传到一个git仓库里。
步骤二
1 启动jenkins,新建item,构建一个自由风格的项目,输入名称点击确定,接下来就是job配置。

新建item

2 主要配置后五项,源码管理,构建触发器,构建环境,构建,构建后操作。
项目配置

3 源码管理


源码管理

这里就是填写你的仓库路径,授权账户,分支。

4 构建触发器


构建触发器

这里根据不同的需求,可以自定义触发脚本运行时机。这里设置构建触发器*/2 * * * *,每2分钟检查一次源码变化。

5 构建环境
此项可不用配置

6 构建
增加构建步骤,选择Execute 脚本

输入脚本:

#!/bin/bash -l

  #新建目录用于保存报告

  mkdir test-reports

  #pod可能失败的全局参数设置

  export LANG=en_US.UTF-8

  export LANGUAGE=en_US.UTF-8

  export LC_ALL=en_US.UTF-8

  pod install

  #xcodebuild test -workspace XXX.xcworkspace -scheme XXXTests -destination 'platform=iOS Simulator,name=iPhone 6s'跑[<u style="margin: 0px auto; padding: 0px; font-family: &quot;microsoft yahei&quot;;">**测试用例**</u>](javascript:;)

  #-enableCodeCoverage YES 收集[<u style="margin: 0px auto; padding: 0px; font-family: &quot;microsoft yahei&quot;;">**测试覆盖率**</u>](javascript:;)

  #ocunit2junit 输出报告转换为jenkins可读的[<u style="margin: 0px auto; padding: 0px; font-family: &quot;microsoft yahei&quot;;">**junit**</u>](javascript:;)报告

  xcodebuild test -workspace XXX.xcworkspace -scheme XXXTests -destination 'platform=iOS Simulator,name=iPhone 6s' -configuration Debug -enableCodeCoverage YES 2>&1 | ocunit2junit

  #slather coverage转换覆盖率报告为html文件,jenkins可读

  #--input-format profdata  xcode生成的为profdata格式的文件,转换为html以便jenkins显示

  #--ignore 排除筛选需要计算的文件,多个格式写多个ignore表达式

  slather coverage --html --input-format profdata --binary-basename XXXApp --scheme XXXTests --workspace XXX.xcworkspace --configuration Debug --ignore **View** --ignore **AppText** --output-directory reports XXX.xcodeproj

这里用到两个工具, ocunit2junit 以及slather.
打开mac终端安装

sudo gem install ocunit2junit
sudo gem install slather

7 构建后操作
读取显示junit和覆盖率html报告
  这里用到两个jenkins插件,jenkins->系统管理-> 管理插件,找到JUnit Plugin和HTML Publisher plugin,安装重启jenkins,如果没安装这两个插件的话,构建后操作步骤是没有这两个选项的

选择Publish Junit test result report,配置xml文件路径为第三步配置的test-reports/*.xml。

再增加一个构建后操作,选择Publish HTML reports, 配置html路劲为第三步配置的reports,Index文件为index.html,可以设置标题Reports title为Coverage Report。

保存返回,点击立即构建,等待构建完成,返回job主页,可以看到junit测试结果报告和覆盖率的图表了。


UI自动化构建结果

到此整个jenkins集成完毕了,以后就可以愉快的跑UI测试了

六. 总结

项目中对于单元测试,UI测试我们可以单独拉取一个分支,专门作为测试分支,每次代码提交前,先合并到这个测试分支,然后jenkins就会开始跑你所有的测试用例,如果我们写了很多测试用例,有很多个测试用例文件,我们要指定跑哪几个怎么办,看下图:


image.png

EditScheme->Test
把你不想跑的测试用例直接勾掉就行了,然后保存推送到git仓库就行了,这里还有一个注意的,上文讲的覆盖率报告的生成,这里有个Code Coverage选项要勾上才行。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,298评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,701评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,078评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,687评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,018评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,410评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,729评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,412评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,124评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,379评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,903评论 1 257
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,268评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,894评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,014评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,770评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,435评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,312评论 2 260

推荐阅读更多精彩内容