這段時(shí)間在團(tuán)隊(duì)里一直在負(fù)責(zé)對(duì)單元測(cè)試的探索和落地,感覺有必要總結(jié)下自己這段時(shí)間的探索成果和大家分享。加之已經(jīng)忙的很久沒寫博客了,感覺沒有沉淀,這樣不好。iOS單元測(cè)試系列會(huì)一直更新,按主題將我在單元測(cè)試探索和落地過程中的技術(shù)積累沉淀下來,也算是對(duì)自己這段時(shí)間的總結(jié)。部分觀點(diǎn)是我個(gè)人觀點(diǎn),歡迎大家討論。
一開始接到的不是單元測(cè)試的任務(wù),而是與測(cè)試同學(xué)共建完成iOS上持續(xù)集成能跑測(cè)試用例的平臺(tái)。然后我就吭哧吭哧的區(qū)研究Jenkins,后來發(fā)現(xiàn)不對(duì),就算我把平臺(tái)搭建好了沒有測(cè)試用例也只是個(gè)空殼子,而應(yīng)該合理分工,測(cè)試同學(xué)負(fù)責(zé)搭建平臺(tái),開發(fā)負(fù)責(zé)寫測(cè)試用例。
XCTest Or GHUnit
寫測(cè)試用例總得有個(gè)框架吧,現(xiàn)在比較流行的就屬Apple自帶的XCTest和第三方的GHUnit。我們來看看他兩之間的區(qū)別。
XCTest:與Xcode深度集成。而且可以享受Apple后續(xù)對(duì)XCTest升級(jí)的福利。
GHUnit:集成度不如XCTest,安裝麻煩。但是有自己的GUI界面。
貌似都各有所長(zhǎng),那么我們來看看Github上的一些知名的開源庫都用的是什么測(cè)試框架吧。

可以看到清一色的被XCTest刷屏了。也的確,GHUnit的GUI界面對(duì)我們來說沒有什么特別大的意義。而XCTest血統(tǒng)純正,背后站著東家Apple。而對(duì)于我們的選擇也應(yīng)該是XCTest,應(yīng)該既然Github上又這么多XCTest的case例子可以參考,對(duì)我們的幫助肯定不言而喻。
OCMock Or OCMockito
這兩個(gè)都是用來mock對(duì)象,stub方法的。OCMock 和 OCMockito個(gè)人感覺功能區(qū)別不大。他們之間的區(qū)別在于使用OCMock的庫比OCMockito的庫多,而且文檔和教程更加豐富。大家可以打開OCMock官網(wǎng)看一下。所以個(gè)人選擇我選了OCMock作為我們的測(cè)試mock工具。
Expecta Or OCHamcrest
Expecta和OCHamcrest這兩個(gè)都是斷言的擴(kuò)展框架。一開始我選擇了Expecta,因?yàn)槲液髞碛幸欢螘r(shí)間將測(cè)試文件用BDD框架Specta來寫(當(dāng)然這是后話),而Expecta 和Specta都出自同一個(gè)人之手,不論是教程文檔都更加豐富。但是后來我廢棄了BDD框架,還是用原生的XCTest,Expecta在使用中也遇到了一些問題,我就把我們的斷言框架由Expecta切換到了OCHamcrest。
原因有兩點(diǎn):
1.Expecta不成熟,至筆者切換的時(shí)候才0.3.1版本,遇到很多框架自身的問題。case跑著跑著驗(yàn)證通不過了,再跑一次又過了,是不是還爆出個(gè)Expecta框架內(nèi)部的crash。
2.OCHamcrest更加成熟,而且可擴(kuò)展性高,可以自定義自己的斷言,更靈活。
比如OCHamcrest不支持superClass驗(yàn)證,我們必須自己去比較,返回一個(gè)bool值,然后去判斷bool是否為真。很麻煩。自己自定義個(gè)superClass的驗(yàn)證,就不需要每次都這么麻煩的寫這么多代碼了。而如果Expecta不支持的斷言,那就永遠(yuǎn)不能支持了。
我們可以通過OCHamcrest這個(gè)特性,做一些符合自己app場(chǎng)景的特有斷言。
BDD Or Not
BDD的全稱是Behavior Driven Development。也就是行為驅(qū)動(dòng)開發(fā)。BDD確實(shí)讓我眼前一亮。他能將測(cè)試語言寫成類似自然語言。BDD的理念是你不是在寫代碼,而是在講故事。而整個(gè)故事是由Given...When...Then組成。我們可以來看看BDD框架Kiwi的一段測(cè)試代碼:
describe(@"Team", ^{
context(@"when newly created", ^{
it(@"has a name", ^{
id team = [Team team];
[[team.name should] equal:@"Black Hawks"];
});
it(@"has 11 players", ^{
id team = [Team team];
[[[team should] have:11] players];
});
});
});
這個(gè)測(cè)試用例就是在說Given a Team,When newly created,it should have a name, and should have 11 players。
的確很清晰,基本不需要注釋就能知道在干嘛了。
既然BDD這么好,那么我們比較下BDD框架Kiwi和XCTest + OCMock組合的優(yōu)劣吧。為什么是XCTest + OCMock而不是XCTest,因?yàn)镵iwi自帶mock功能,而XCTest沒有mock功能。

可以看出Kiwi還是蠻誘人的。但是Kiwi的mock功能api遠(yuǎn)沒有OCMock設(shè)計(jì)的好,尤其是OCMock3推出后,所以筆者想把Kiwi和OCMock一起用,結(jié)果這兩個(gè)庫存在不兼容性。一跑就掛。后來遷移到BDD另一個(gè)框架Specta,BDD的理念相同,所以語法也大同小異。Specta和Kiwi的區(qū)別就是Kiwi包含了Specta和OCmock以及Expeata所有的功能。換句話說Specta就是沒有mock和驗(yàn)證功能的kiwi。但是想對(duì)來說,specta的API設(shè)計(jì)更加合理。
但是,高潮來了!后續(xù)我還是廢棄了BDD,切換回XCTest,原因有很多。主要的原因是BDD框架hold不住業(yè)務(wù)的發(fā)展,BDD的講故事理念在業(yè)務(wù)面前就是老太太的裹腳布,又臭又長(zhǎng)!而且BDD需要一定的學(xué)習(xí)成本,不像XCTest這種類JUnit的對(duì)開發(fā)者更友好的代碼。而且BDD的框架包裝過深,可擴(kuò)展性不高。還有就是BDD的框架普遍太年輕,bug相對(duì)較多,版本迭代太快。最最致命的是BDD的框架不能單個(gè)case單個(gè)跑,一跑所有的case全部跑一邊這在平時(shí)寫case 的時(shí)候是非常拖沓的!
總結(jié)
也沒啥好總結(jié)的。一個(gè)個(gè)坑踩下來,最后的選擇是XCTest + OCMock + OCHamcrest是我認(rèn)為最好的框架方案。當(dāng)然,這是我的個(gè)人觀點(diǎn)~