iOS 自動(dòng)化測(cè)試的那些干貨

前言

如果有測(cè)試大佬發(fā)現(xiàn)內(nèi)容不對(duì),歡迎指正,我會(huì)及時(shí)修改。

大多數(shù)的iOS App(沒有持續(xù)集成)迭代流程是這樣的

也就是說(shuō)驾孔,測(cè)試是發(fā)布之前的最后一道關(guān)卡。如果bug不能在測(cè)試中發(fā)現(xiàn)惯疙,那么bug

就會(huì)抵達(dá)用戶翠勉,所以測(cè)試的完整性和可靠性十分重要。

目前螟碎,大多數(shù)App還停留在人工測(cè)試階段眉菱,人工測(cè)試投入的成本最低,能夠保證核心功能的使用掉分,而且測(cè)試人員不需要會(huì)寫代碼俭缓。

但是克伊,在很多測(cè)試場(chǎng)景下,人工測(cè)試的效率太低华坦,容易出錯(cuò)愿吹。舉兩個(gè)常見的例子:

一個(gè)App的核心功能,在每一次發(fā)布版本前的測(cè)試必定會(huì)跑一遍所有的測(cè)試用例惜姐,不管對(duì)應(yīng)的業(yè)務(wù)在當(dāng)前版本有沒有變化(天知道開發(fā)在做業(yè)務(wù)A的時(shí)候犁跪,對(duì)業(yè)務(wù)B有沒有影響),如果這次測(cè)出新的bug歹袁,測(cè)試人員在下一次發(fā)版測(cè)試中坷衍,又不得不做這些重復(fù)的工作挣饥。

開發(fā)在寫API請(qǐng)求相關(guān)代碼的時(shí)候沒有做數(shù)據(jù)容錯(cuò)帆赢,測(cè)試在人工測(cè)試的時(shí)候都是正常的數(shù)據(jù)公你,所以測(cè)試通過谨胞。上線了之后,后臺(tái)配置數(shù)據(jù)的時(shí)候出了點(diǎn)小問題谍肤,導(dǎo)致大面積崩潰胧砰,boom~唉匾。

然后凄硼,老板就要過來(lái)找你了

本文所講解的均是基于XCode 8.2.1铅协,有些概念可能不適用于低版本的XCode

自動(dòng)化測(cè)試

自動(dòng)化測(cè)試就是寫一些測(cè)試代碼,用代碼代替人工去完成模塊和業(yè)務(wù)的測(cè)試摊沉。

其實(shí)不管是開發(fā)還是測(cè)試狐史,如果你在不斷的做重復(fù)性工作的時(shí)候,就應(yīng)該問自己一個(gè)問題:是不是有更高效的辦法说墨?

自動(dòng)化測(cè)試有很多優(yōu)點(diǎn):

測(cè)試速度快预皇,避免重復(fù)性的工作

避免regression,讓開發(fā)更有信心去修改和重構(gòu)代碼(個(gè)人認(rèn)為最大的優(yōu)點(diǎn))

具有一致性婉刀。

有了自動(dòng)化測(cè)試,持續(xù)集成(CI)會(huì)變得更可靠序仙。

迫使開發(fā)人員寫出更高質(zhì)量的代碼突颊。(自動(dòng)化測(cè)試不通過,代碼不允許合并)

當(dāng)然潘悼,自動(dòng)化測(cè)試也有一些缺點(diǎn)律秃。

開發(fā)和維護(hù)成本高。

不能完全替代人工測(cè)試治唤。

無(wú)法完全保證測(cè)試的準(zhǔn)確性 – 讓代碼去判斷一段邏輯是否正確很容易棒动,但是,讓代碼判斷一個(gè)控件顯示是否正確卻沒那么容易宾添。

所以船惨,在做自動(dòng)化測(cè)試之前柜裸,首先要問自己幾個(gè)問題?

這個(gè)測(cè)試業(yè)務(wù)的變動(dòng)是否頻繁粱锐?

這個(gè)測(cè)試業(yè)務(wù)是否屬于核心功能疙挺?

編寫測(cè)試代碼的成本有多少?

自動(dòng)化測(cè)試能保證測(cè)試結(jié)果的準(zhǔn)確么怜浅?

通常铐然,我們會(huì)選擇那些業(yè)務(wù)穩(wěn)定,需要頻繁測(cè)試的部分來(lái)編寫自動(dòng)化測(cè)試腳本恶座,其余的采用人工測(cè)試搀暑,人工測(cè)試仍然是iOS App開發(fā)中不可缺少的一部分。

測(cè)試種類

從是否接觸源代碼的角度來(lái)分類:測(cè)試分為黑盒和白盒(灰盒就是黑盒白盒結(jié)合跨琳,這里不做討論)自点。

白盒測(cè)試的時(shí)候,測(cè)試人員是可以直接接觸待測(cè)試App的源代碼的湾宙。白盒測(cè)試更多的是單元測(cè)試樟氢,測(cè)試人員針對(duì)各個(gè)單元進(jìn)行各種可能的輸入分析,然后測(cè)試其輸出侠鳄。白盒測(cè)試的測(cè)試代碼通常由iOS開發(fā)編寫埠啃。

黑盒測(cè)試。黑盒測(cè)試的時(shí)候伟恶,測(cè)試人員不需要接觸源代碼碴开。是從App層面對(duì)其行為以及UI的正確性進(jìn)行驗(yàn)證,黑盒測(cè)試由iOS測(cè)試完成博秫。

從業(yè)務(wù)的層次上來(lái)說(shuō)潦牛,測(cè)試金字塔如圖:

而iOS測(cè)試通常只有以下兩個(gè)層次:

Unit,單元測(cè)試挡育,保證每一個(gè)類能夠正常工作

UI巴碗,UI測(cè)試,也叫做集成測(cè)試即寒,從業(yè)務(wù)層的角度保證各個(gè)業(yè)務(wù)可以正常工作橡淆。

框架選擇

啰里八嗦講的這么多,自動(dòng)化測(cè)試的效率怎么樣母赵,關(guān)鍵還是在測(cè)試框架上逸爵。那么,如何選擇測(cè)試框架呢凹嘲?框架可以分為兩大類:XCode內(nèi)置的和三方庫(kù)师倔。

選擇框架的時(shí)候有幾個(gè)方面要考慮

測(cè)試代碼編寫的成本

是否可調(diào)式

框架的穩(wěn)定性

測(cè)試報(bào)告(截圖,代碼覆蓋率周蹭,…)

WebView的支持(很多App都用到了H5)

自定義控件的測(cè)試

是否需要源代碼

能否需要連著電腦

是否支持CI(持續(xù)集成)

….

我們首先來(lái)看看XCode內(nèi)置的框架:XCTest趋艘。XCTest又可以分為兩部分:Unit

Test 和 UI

Test疲恢,分別對(duì)應(yīng)單元測(cè)試和UI測(cè)試。有一些三方的測(cè)試庫(kù)也是基于XCTest框架的致稀,這個(gè)在后文會(huì)講到冈闭。由于是Apple官方提供的,所以這個(gè)框架會(huì)不斷完善抖单。

成熟的三方框架通常提供了很多封裝好的有好的接口萎攒,筆者綜合對(duì)比了一些,推薦以下框架:

單元測(cè)試:

以下三個(gè)框架都是BDD(Behavior-driven

development) – 行為驅(qū)動(dòng)開發(fā)矛绘。行為驅(qū)動(dòng)開發(fā)簡(jiǎn)單來(lái)說(shuō)就是先定義行為耍休,然后定義測(cè)試用例,接著再編寫代碼货矮。

實(shí)踐中發(fā)現(xiàn)羊精,通常沒有那么多時(shí)間來(lái)先定義行為,不過BDD中的domain-specific language (DSL)能夠很好的描述用例的行為囚玫。

Kiwi 老牌測(cè)試框架

specta 另一個(gè)BDD優(yōu)秀框架

Quick 三個(gè)項(xiàng)目中Star最多喧锦,支持OC和Swift,優(yōu)先推薦抓督。

UI測(cè)試

KIF 基于XCTest的測(cè)試框架燃少,調(diào)用私有API來(lái)控制UI,測(cè)試用例用Objective C或Swift編寫铃在。

appium 基于Client – Server的測(cè)試框架阵具。App相當(dāng)于一個(gè)Server,測(cè)試代碼相當(dāng)于Client定铜,通過發(fā)送JSON來(lái)操作APP阳液,測(cè)試語(yǔ)言可以是任意的,支持android和iOS揣炕。

篇幅有限帘皿,本文會(huì)先介紹XCtest,接著三方的Unit框架會(huì)以Quick為例畸陡,UI Test框架側(cè)重分析KIF矮烹,appium僅僅做原理講解。

XCTest

對(duì)于XCTest來(lái)說(shuō)罩锐,最后生成的是一個(gè)bundle。bundle是不能直接執(zhí)行的卤唉,必須依賴于一個(gè)宿主進(jìn)程涩惑。關(guān)于XCTest進(jìn)行單元測(cè)試的基礎(chǔ)(XCode的使用,異步測(cè)試桑驱,性能測(cè)試竭恬,代碼覆蓋率等)跛蛋,我在這篇文章里講解過,這里不再詳細(xì)講解痊硕。

iOS 單元測(cè)試之XCTest詳解

blog.csdn.net/hello_hwc/article/details/46671053

單元測(cè)試用例

比如赊级,我有以下一個(gè)函數(shù):

//驗(yàn)證一段Text是否有效。(不能以空字符開頭岔绸,不能為空)

-(BOOL)validText:(NSString *)texterror:(NSError *__autoreleasing *)error{

}

那么理逊,我該如何為這個(gè)函數(shù)編寫單元測(cè)試的代碼?通常盒揉,需要考慮以下用例:

輸入以空白字符或者換行符開頭的晋被,error不為空,返回 NO

輸入正確的內(nèi)容刚盈,error為空羡洛,返回YES

輸入為nil,error不為空,返回 NO (邊界條件)

輸入為非NSString類型藕漱,驗(yàn)證不通過欲侮,返回NO (錯(cuò)誤輸入)

特殊輸入字符(標(biāo)點(diǎn)符號(hào),非英文等等)

UI測(cè)試

UI測(cè)試是模擬用戶操作肋联,進(jìn)而從業(yè)務(wù)處層面測(cè)試威蕉。關(guān)于XCTest的UI測(cè)試,建議看看WWDC 2015的這個(gè)視頻:

UI Testing in Xcode

https://developer.apple.com/videos/play/wwdc2015/406/

關(guān)于UI測(cè)試牺蹄,有幾個(gè)核心類需要掌握

XCUIApplication 測(cè)試應(yīng)用的代理

XCUIElement 一個(gè)UI上可見的視圖對(duì)象

XCUIElementQuery 查找XCUIElement

UI測(cè)試還有一個(gè)核心功能是UI Recording忘伞。選中一個(gè)UI測(cè)試用例,然后點(diǎn)擊圖中的小紅點(diǎn)既可以開始UI Recoding沙兰。你會(huì)發(fā)現(xiàn):

隨著點(diǎn)擊模擬器氓奈,自動(dòng)合成了測(cè)試代碼。(通常自動(dòng)合成代碼后鼎天,還需要手動(dòng)的去調(diào)整)

在寫UI測(cè)試用例的時(shí)候要注意:測(cè)試行為而不是測(cè)試代碼舀奶。比如,我們測(cè)試這樣一個(gè)case

進(jìn)入Todo首頁(yè)斋射,點(diǎn)擊add育勺,進(jìn)入添加頁(yè)面,輸入文字罗岖,點(diǎn)擊save涧至。

測(cè)試效果如下:


對(duì)應(yīng)測(cè)試代碼:

-(void)testAddNewItems{

//獲取app代理

XCUIApplication *app=[[XCUIApplicationalloc]init];

//找到第一個(gè)tabeview,就是我們想要的tableview

XCUIElement *table=[app.tableselementBoundByIndex:0];

//記錄下來(lái)添加之前的數(shù)量

NSIntegeroldCount=table.cells.count;

//點(diǎn)擊Add

[app.navigationBars[@"ToDo"].buttons[@"Add"]tap];

//找到Textfield

XCUIElement *inputWhatYouWantTodoTextField=app.textFields[@"Input what you want todo"];

//點(diǎn)擊Textfield

[inputWhatYouWantTodoTextFieldtap];

//輸入字符

[inputWhatYouWantTodoTextFieldtypeText:@"somethingtodo"];

//點(diǎn)擊保存

[app.navigationBars[@"Add"].buttons[@"Save"]tap];

//獲取當(dāng)前的數(shù)量

NSIntegernewCount=table.cells.count;

//如果cells的數(shù)量加一桑包,則認(rèn)為測(cè)試成功

XCTAssert(newCount==oldCount+1);

}

這里是通過前后tableview的row數(shù)量來(lái)斷言成功或者失敗南蓬。

等待

通常,在視圖切換的時(shí)候有轉(zhuǎn)場(chǎng)動(dòng)畫,我們需要等待動(dòng)畫結(jié)束,然后才能繼續(xù)赘方,否則query的時(shí)候很可能找不到我們想要的控件烧颖。

比如,如下代碼等待VC轉(zhuǎn)場(chǎng)結(jié)束窄陡,當(dāng)query只有一個(gè)table的時(shí)候炕淮,才繼續(xù)執(zhí)行后續(xù)的代碼。

[selfexpectationForPredicate:[NSPredicatepredicateWithFormat:@"self.count = 1"]

evaluatedWithObject:app.tables

handler:nil];

[selfwaitForExpectationsWithTimeout:2.0handler:nil];

//后續(xù)代碼....

Tips: 當(dāng)你的UI結(jié)構(gòu)比較復(fù)雜的時(shí)候跳夭,比如各種嵌套childViewController涂圆,使用XCUIElementQuery的代碼會(huì)很長(zhǎng),也不好維護(hù)优妙。

另外乘综,UI測(cè)試還會(huì)在每一步操作的時(shí)候截圖,方便對(duì)測(cè)試報(bào)告進(jìn)行驗(yàn)證套硼。

查看測(cè)試結(jié)果

使用基于XCTest的框架卡辰,可以在XCode的report navigator中查看測(cè)試結(jié)果。

其中:

Tests 用來(lái)查看詳細(xì)的測(cè)試過程

Coverage 用來(lái)查看代碼覆蓋率

Logs 用來(lái)查看測(cè)試的日志

點(diǎn)擊圖中的紅色框指向的圖標(biāo)可以看到每一步UI操作的截圖

除了利用XCode的GUI邪意,還可以通過后文提到的命令行工具來(lái)測(cè)試九妈,查看結(jié)果。

Stub/Mock

首先解釋兩個(gè)術(shù)語(yǔ):

mock 表示一個(gè)模擬對(duì)象

stub 追蹤方法的調(diào)用雾鬼,在方法調(diào)用的時(shí)候返回指定的值萌朱。

通常,如果你采用純存的XCTest策菜,推薦采用OCMock來(lái)實(shí)現(xiàn)mock和stub晶疼,單元測(cè)試的三方庫(kù)通常已集成了stub和mock。

那么又憨,如何使用mock呢翠霍?舉個(gè)官方的例子:

//mock一個(gè)NSUserDefaults對(duì)象

iduserDefaultsMock=OCMClassMock([NSUserDefaultsclass]);

//在調(diào)用stringForKey的時(shí)候,返回http://testurl

OCMStub([userDefaultsMock

stringForKey:@"MyAppURLKey"]).andReturn(@"http://testurl");

再比如蠢莺,我們要測(cè)試打開其他App寒匙,那么如何判斷確實(shí)打開了其他App呢?

idapp=OCMClassMock([UIApplicationclass]);

OCMStub([appsharedInstance]).andReturn(app);

OCMVerify([appopenURL:url]

使用Stub可以讓我們很方便的實(shí)現(xiàn)這個(gè)躏将。

關(guān)于OCMock的使用锄弱,推薦看看objc.io的這篇文章

置換測(cè)試: Mock, Stub 和其他

https://objccn.io/issue-15-5/

Quick

Quick是建立在XCTestSuite上的框架,使用XCTestSuite允許你動(dòng)態(tài)創(chuàng)建測(cè)試用例祸憋。所以会宪,使用Quick,你仍讓可以使用XCode的測(cè)試相關(guān)GUI和命令行工具。

使用Quick編寫的測(cè)試用例看起來(lái)是這樣子的:

import Quick

import Nimble

classTableOfContentsSpec:QuickSpec{

override func spec(){

describe("the 'Documentation' directory"){

it("has everything you need to get started"){

letsections=Directory("Documentation").sections

expect(sections).to(contain("Organized Tests with Quick Examples and Example Groups"))

expect(sections).to(contain("Installing Quick"))

}

context("if it doesn't have what you're looking for"){

it("needs to be updated"){

letyou=You(awesome:true)

expect{you.submittedAnIssue}.toEventually(beTruthy())

}

}

}

}

}

BDD的框架讓測(cè)試用例的目的更加明確蚯窥,測(cè)試是否通過更加清晰狈谊。使用Quick,測(cè)試用例分為兩種:

單獨(dú)的用例 – 使用it來(lái)描述

it有兩個(gè)參數(shù)喜命,

行為描述

行為的測(cè)試代碼

比如,以下測(cè)試Dolphin行為河劝,它具有行為is friendly和is smart

//Swift代碼

classDolphinSpec:QuickSpec{

override func spec(){

it("is friendly"){

expect(Dolphin().isFriendly).to(beTruthy())

}

it("is smart"){

expect(Dolphin().isSmart).to(beTruthy())

}

}

}

可以看到,BDD的核心是行為矛紫。也就是說(shuō)赎瞎,需要關(guān)注的是一個(gè)類提供哪些行為。

用例集合颊咬,用describe和context描述

比如务甥,驗(yàn)證dolphin的click行為的時(shí)候,我們需要兩個(gè)用例喳篇。一個(gè)是is loud,一個(gè)是has a high frequency敞临,就可以用describe將用例組織起來(lái)。

classDolphinSpec:QuickSpec{

override func spec(){

describe("a dolphin"){

describe("its click"){

it("is loud"){

letclick=Dolphin().click()

expect(click.isLoud).to(beTruthy())

}

it("has a high frequency"){

letclick=Dolphin().click()

expect(click.hasHighFrequency).to(beTruthy())

}

}

}

}

}

context可以指定用例的條件:

比如

describe("its click"){

context("when the dolphin is not near anything interesting"){

it("is only emitted once"){

expect(dolphin!.click().count).to(equal(1))

}

}

}

除了這些之外麸澜,Quick也支持一些切入點(diǎn)挺尿,進(jìn)行測(cè)試前的配置:

beforeEach

afterEach

beforeAll

afterAll

beforeSuite

afterSuite

Nimble

由于Quick是基于XCTest,開發(fā)者當(dāng)然可以收使用斷言來(lái)定義測(cè)試用例成功或者失敗炊邦。Quick提供了一個(gè)更有好的Framework來(lái)進(jìn)行這種斷言:https://github.com/Quick/Nimble

比如编矾,一個(gè)常見的XCTest斷言如下:

XCTAssertTrue(ConditionCode,"FailReason")

在出錯(cuò)的時(shí)候,會(huì)提示

XCAssertTrue failed, balabala

這時(shí)候馁害,開發(fā)者要打個(gè)斷點(diǎn)窄俏,查看下上下文,看看具體失敗的原因在哪碘菜。

使用Nimble后凹蜈,斷言變成類似

expect(1+1).to(equal(2))

expect(3)>2

expect("seahorse").to(contain("sea"))

expect(["Atlantic","Pacific"]).toNot(contain("Mississippi"))

并且,出錯(cuò)的時(shí)候忍啸,提示信息會(huì)帶著上下文的值信息仰坦,讓開發(fā)者更容易的找到錯(cuò)誤。

讓你的代碼更容易單元測(cè)試

測(cè)試的準(zhǔn)確性和工作量很大程度上依賴于開發(fā)人員的代碼質(zhì)量吊骤。

通常缎岗,為了單元測(cè)試的準(zhǔn)確性,我們?cè)趯懞瘮?shù)(方法)的時(shí)候會(huì)借鑒一些函數(shù)式編程的思想白粉。其中最重要的一個(gè)思想就是

pure function(純函數(shù))

何為Pure function传泊?就是如果一個(gè)函數(shù)的輸入一樣,那么輸出一定一樣鸭巴。

比如眷细,這樣的一個(gè)函數(shù)就不是pure function。因?yàn)樗蕾囉谕獠孔兞縱alue的值鹃祖。

staticNSIntegervalue=0;

-(NSInteger)function_1{

value=value+1;

returnvalue;

}

而這個(gè)函數(shù)就是pure function溪椎,因?yàn)榻o定輸入,輸出一定一致。

-(NSInteger)function_2:(NSInteger)base{

NSIntegervalue=base+1;

returnvalue;

}

所以校读,如果你寫了一個(gè)沒有參數(shù)沼侣,或者沒有返回值的方法,那么你要小心了歉秫,很可能這個(gè)方法很難測(cè)試蛾洛。

關(guān)于MVC

在良好的MVC架構(gòu)的App中,

View只做純粹的展示型工作雁芙,把用戶交互通過各種方式傳遞到外部

Model只做數(shù)據(jù)存儲(chǔ)類工作

Controller作為View和Model的樞紐轧膘,往往要和很多View和Model進(jìn)行交互,也是自動(dòng)化包括代碼維護(hù)的痛點(diǎn)兔甘。

所以谎碍,對(duì)Controller瘦身是iOS架構(gòu)中比較重要的一環(huán),一些通用的技巧包括:

邏輯抽離:

網(wǎng)絡(luò)請(qǐng)求獨(dú)立洞焙◇〉恚可以每個(gè)網(wǎng)絡(luò)請(qǐng)求以Command模式封裝成一個(gè)對(duì)象,不要直接在Controller調(diào)用AFNetworking闽晦。

數(shù)據(jù)存儲(chǔ)獨(dú)立扳碍。建立獨(dú)立的Store類,用來(lái)做數(shù)據(jù)持久化和緩存仙蛉。

共有數(shù)據(jù)服務(wù)化(協(xié)議)笋敞。比如登錄狀態(tài)等等,通過服務(wù)去訪問荠瘪,這樣服務(wù)提供者之需要處理服務(wù)的質(zhì)量夯巷,服務(wù)使用者則信任服務(wù)提供者的結(jié)果。

Controller與View解耦合

建立ViewModel層哀墓,這樣Controller只需要和ViewModel進(jìn)行交互趁餐。

建立UIView子類作為容器,將一些View放到容器后再把容器作為SubView添加到Controller里

建立可復(fù)用的Layout層篮绰,不管是AutoLayout還是手動(dòng)布局后雷。

Controller與Controller解耦合

建立頁(yè)面路由。每一個(gè)界面都抽象為一個(gè)URL吠各,跳轉(zhuǎn)僅僅通過Intent或者URL跳轉(zhuǎn)臀突,這樣兩個(gè)Controller完全獨(dú)立。

如果你的App用Swift開發(fā)贾漏,那么面向協(xié)議編程和不可變的值類型會(huì)讓你的代碼更容易測(cè)試候学。

當(dāng)然,iOS組建化對(duì)自動(dòng)化測(cè)試的幫助也很大纵散,因?yàn)椴还苁腔A(chǔ)組件還是業(yè)務(wù)組件梳码,都可以獨(dú)立測(cè)試隐圾。組建化又是一個(gè)很大的課題,這里不深入講解了掰茶。

KIF

KIF的全稱是Keep

it

functional暇藏。它是一個(gè)建立在XCTest的UI測(cè)試框架,通過accessibility來(lái)定位具體的控件濒蒋,再利用私有的API來(lái)操作UI叨咖。由于是建立在XCTest上的,所以你可以完美的借助XCode的測(cè)試相關(guān)工具(包括命令行腳本)啊胶。

> KIF是個(gè)人非常推薦的一個(gè)框架,簡(jiǎn)單易用垛贤。

使用KIF框架強(qiáng)制要求你的代碼支持accessibility焰坪。如果你之前沒接觸過,可以看看Apple的文檔

Accessibility Programming Guide for iOS

https://developer.apple.com/library/prerelease/content/documentation/UserExperience/Conceptual/iPhoneAccessibility/Introduction/Introduction.html

簡(jiǎn)單來(lái)說(shuō)聘惦,accessibility能夠讓視覺障礙人士使用你的App某饰。每一個(gè)控件都有一個(gè)描述AccessibilityLabel。在開啟VoiceOver的時(shí)候善绎,點(diǎn)擊控件就可以選中并且聽到對(duì)應(yīng)的描述黔漂。

通常UIKit的控件是支持accessibility的,自定定義控件可以通過代碼或者Storyboard上設(shè)置禀酱。

在Storyboard上設(shè)置:

上面的通過Runtime Attributes設(shè)置(KVC)

下面的通過GUI來(lái)設(shè)置

通過代碼設(shè)置:

[alertsetAccessibilityLabel:@"Label"];

[alertsetAccessibilityValue:@"Value"];

[alertsetAccessibilityTraits:UIAccessibilityTraitButton];

如果你有些Accessibility的經(jīng)驗(yàn)炬守,那么你肯定知道,像TableView的這種不應(yīng)該支持VoiceOver的剂跟。我們可以用條件編譯來(lái)只對(duì)測(cè)試Target進(jìn)行設(shè)置:

#ifdef DEBUG

[tableViewsetAccessibilityValue:@"Main List Table"];

#endif

#ifdef KIF_TARGET (這個(gè)值需要在build settings里設(shè)置)

[tableViewsetAccessibilityValue:@"Main List Table"];

#endif

使用KIF主要有兩個(gè)核心類:

KIFTestCase XCTestCase的子類

KIFUITestActor 控制UI减途,常見的三種是:點(diǎn)擊一個(gè)View,向一個(gè)View輸入內(nèi)容曹洽,等待一個(gè)View的出現(xiàn)

我們用KIF來(lái)測(cè)試添加一個(gè)新的ToDo

-(void)testAddANewItem{

[testertapViewWithAccessibilityLabel:@"Add"];

[testerenterText:@"Create a test to do item"intoViewWithAccessibilityLabel:@"Input what you want todo"];

[testertapViewWithAccessibilityLabel:@"Save"];

[testerwaitForTimeInterval:0.2];

[testerwaitForViewWithAccessibilityLabel:@"Create a test to do item"];

}

命令行

自動(dòng)化測(cè)試中鳍置,命令行工具可以facebook的開源項(xiàng)目:

xctool

這是一個(gè)基于xcodebuild命令的擴(kuò)展,在iOS自動(dòng)化測(cè)試和持續(xù)集成領(lǐng)域很有用,而且它支持-parallelize并行測(cè)試多個(gè)bundle送淆,大大提高測(cè)試效率税产。

安裝XCTool,

brew installxctool

使用

path/to/xctool.sh

-workspaceYourWorkspace.xcworkspace

-schemeYourScheme

-reporterplain:/path/to/plain-output.txt

run-test

并且,xctool對(duì)于持續(xù)集成很有用偷崩,iOS常用的持續(xù)集成的server有兩個(gè):

Travis CI 對(duì)于公開倉(cāng)庫(kù)(比如github)免費(fèi)辟拷,私有倉(cāng)庫(kù)收費(fèi)

Jenkins 免費(fèi)

優(yōu)化你的測(cè)試代碼

準(zhǔn)確的測(cè)試用例

通常,你的你的測(cè)試用例分為三部分:

配置測(cè)試的初始狀態(tài)

對(duì)要測(cè)試的目標(biāo)執(zhí)行代碼

對(duì)測(cè)試結(jié)果進(jìn)行斷言(成功 or 失敾吩洹)

測(cè)試代碼結(jié)構(gòu)

當(dāng)測(cè)試用例多了梧兼,你會(huì)發(fā)現(xiàn)測(cè)試代碼編寫和維護(hù)也是一個(gè)技術(shù)活。通常智听,我們會(huì)從幾個(gè)角度考慮:

不要測(cè)試私有方法(封裝是OOP的核心思想之一羽杰,不要為了測(cè)試破壞封裝)

對(duì)用例分組(功能渡紫,業(yè)務(wù)相似)

對(duì)單個(gè)用例保證測(cè)試獨(dú)立(不受之前測(cè)試的影響,不影響之后的測(cè)試)考赛,這也是測(cè)試是否準(zhǔn)確的核心惕澎。

提取公共的代碼和操作,減少copy/paste這類工作颜骤,測(cè)試用例是上層調(diào)用唧喉,只關(guān)心業(yè)務(wù)邏輯,不關(guān)心內(nèi)部代碼實(shí)現(xiàn)忍抽。

一個(gè)常見的測(cè)試代碼組織如下:

appium

appium采用了Client

Server的模式八孝。對(duì)于App來(lái)說(shuō)就是一個(gè)Server,基于WebDriver JSON wire

protocol對(duì)實(shí)際的UI操作庫(kù)進(jìn)行了封裝鸠项,并且暴露出RESTFUL的接口干跛。然后測(cè)試代碼通過HTTP請(qǐng)求的方式,來(lái)進(jìn)行實(shí)際的測(cè)試祟绊。其中楼入,實(shí)際驅(qū)動(dòng)UI的框架根據(jù)系統(tǒng)版本有所不同:

< 9.3 采用UIAutomation

>= 9.3 XCUITest

原因也比較簡(jiǎn)單:Apple在10.0之后,移除了UIAutomation的支持牧抽,只支持XCUITest嘉熊。

對(duì)比KIF,appium有它的優(yōu)點(diǎn):

跨平臺(tái)扬舒,支持iOS阐肤,Android

測(cè)試代碼可以由多種語(yǔ)言編寫,這對(duì)測(cè)試來(lái)說(shuō)門檻更低

測(cè)試腳本獨(dú)立與源代碼和測(cè)試框架

當(dāng)然呼巴,任何框架都有缺點(diǎn):

自定義控件支持不好

WebView的支持不好

總結(jié)

由于我不是專業(yè)的iOS測(cè)試泽腮,關(guān)于測(cè)試的一點(diǎn)見解如下:

單元測(cè)試還是選擇BDD框架,畢竟可讀性高一些衣赶,推薦Quick(Swift)诊赊,Kiwi(Objective C)

UI測(cè)試優(yōu)先推薦KIF,如果需要兼顧安卓測(cè)試府瞄,或者測(cè)試人員對(duì)OC/Swift很陌生碧磅,可以采用appium

參考資料

Testing with Xcode 官方文檔,關(guān)于XCTest以及XCode有詳細(xì)的講解

objc.io關(guān)于測(cè)試的資料對(duì)于官方文檔的補(bǔ)充

騰訊移動(dòng)品質(zhì)中心 鵝廠移動(dòng)品質(zhì)中心遵馆,有很多好文章鲸郊,強(qiáng)力推薦。

基于 KIF 的 iOS UI 自動(dòng)化測(cè)試和持續(xù)集成 美團(tuán)點(diǎn)評(píng)技術(shù)團(tuán)隊(duì)寫的一篇博客

testing-in-swift

微信讀書排版引擎自動(dòng)化測(cè)試方案

原文地址:iOS 自動(dòng)化測(cè)試的那些干貨?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末货邓,一起剝皮案震驚了整個(gè)濱河市秆撮,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌换况,老刑警劉巖职辨,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盗蟆,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡舒裤,警方通過查閱死者的電腦和手機(jī)喳资,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腾供,“玉大人仆邓,你說(shuō)我怎么就攤上這事“楸睿” “怎么了节值?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)榜聂。 經(jīng)常有香客問我察署,道長(zhǎng),這世上最難降的妖魔是什么峻汉? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮脐往,結(jié)果婚禮上休吠,老公的妹妹穿的比我還像新娘。我一直安慰自己业簿,他們只是感情好瘤礁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著梅尤,像睡著了一般柜思。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上巷燥,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天赡盘,我揣著相機(jī)與錄音,去河邊找鬼缰揪。 笑死陨享,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的钝腺。 我是一名探鬼主播抛姑,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼艳狐!你這毒婦竟也來(lái)了定硝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤毫目,失蹤者是張志新(化名)和其女友劉穎蔬啡,沒想到半個(gè)月后诲侮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡星爪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年浆西,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顽腾。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡近零,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抄肖,到底是詐尸還是另有隱情久信,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布漓摩,位于F島的核電站裙士,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏管毙。R本人自食惡果不足惜腿椎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望夭咬。 院中可真熱鬧啃炸,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至裹虫,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間融击,已是汗流浹背筑公。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留尊浪,地道東北人十酣。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像际长,于是被迫代替她去往敵國(guó)和親耸采。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 大多數(shù)的iOS App (沒有持續(xù)集成)迭代流程是這樣的: 也就是說(shuō)工育,測(cè)試是發(fā)布之前的最后一道關(guān)卡虾宇。如果bug不能...
    伯牙呀閱讀 4,869評(píng)論 1 22
  • 不要去動(dòng)那古老的書, 因?yàn)楣爬先绯瘢挥徐`魂嘱朽, 打開它也就濕潤(rùn)了你的眼旭贬, 里面的故事并不出彩, 卻深深的扎痛著你的心搪泳,...
    若梔羽閱讀 499評(píng)論 2 0
  • 若當(dāng)前IP(偏移地址)=1800H稀轨,CS(段基址)=1200H,則存取下一條待取指令的內(nèi)存地址是多少岸军? 【解析】 ...
    0207_孫玲玉閱讀 252評(píng)論 0 0