基於測試驅動的iOS開發

weixin_33890526發表於2016-10-25

第一次接觸基於測試驅動的iOS開發應該是2013年11月那會了。時間過得真快,現在都快三年了。那會Xcode版本還是4.6,單元測試用的OCUnit框架,自從XCode 5之後就變成了XCTest了,Xocde 7 之後又有了UI Testing的測試了,蘋果的測試真是玩的越來越666了。主要的iOS單元測試框架有XCTest,GHUnit,OCMock等。果然,大學裡學的軟體測試專業課還是很有用處的,記得當時老師講的最深刻的還是基於Socket的網路程式設計,一大堆基於測試用例的條件編寫的白盒測試。黑盒測試,系統測試,迴歸測試等等。。。

UI Tests是一個自動測試UI與互動的Testing元件。它可以通過編寫程式碼、或是記錄開發者的操作過程並程式碼化,來實現自動點選某個按鈕、檢視,或者自動輸入文字校驗等功能。

在實際的開發過程中,隨著專案越做越大,功能越來越多,僅僅靠人工操作的方式來覆蓋所有測試用例是非常困難的,尤其是加入新功能以後,舊功能也要重新測試一遍,這導致了測試需要花非常多的時間來進行迴歸測試,這時就產生了大量重複的工作,也會導致上線時間的耽擱。而這些重複的工作有些是可以自動完成的,這時候UI Tests就可以幫助解決這個問題了。

而自動化的測試框架,在Android平臺有較為成熟的Monkey工具,iOS平臺就顯得有點雞肋了。自打Xcode7加入了UI Testing的框架,iOS的自動化測試才有了一片光明。Instrument工具有一項UIAutomation,通過結合Javascript指令碼和Accessibility來推進自動化的步伐。自動生成測試時,先選擇測試檔案後,在除錯區域點選錄製按鈕,就是一個小紅圓點,這時候開始進行操作,它會記錄你的操作步驟,並生成測試程式碼。這時候可以分析測試程式碼的語法,以便你自己手動修改或者手寫測試程式碼

單元測試的魅力

1.她能讓你更自信。幫助你編寫高質量程式碼、減少bug。
如果大家分析一下我們bug原因的構成,我想有會有一部分bug的原因是開發人員在編寫工作程式碼的時候沒有考慮到某些case或者邊際條件。造成這種問題的原因很多,其中很重要的一個原因是我們對工作程式碼所要完成的功能思考不足,而編寫單元測試,特別是先寫單元測試再寫工作程式碼就可以幫助開發人員思考編寫的程式碼到底要實現哪些功能。例如實現一個簡單的使用者註冊功能的業務類方法,用單元測試再寫工作程式碼的方式來工作的話開發人員就會先考慮各種場景相關,例如正常註冊、使用者名稱重複、沒有滿足必要的填寫內容......等等,之後就會編寫相關的測試用例。編寫單元測試程式碼的過程就是促使開發人員思考工作程式碼實現內容和邏輯的過程,之後實現工作程式碼的時候,開發人員思路會更清晰,實現程式碼的質量也會有相應的提升。

2.她能提提升你的戰鬥力。幫助你提升程式碼的反饋速度,減少重複工作,提高開發效率。
開發人員實現某個功能或者修補了某個bug,如果有相應的單元測試支援的話,開發人員可以馬上通過執行單元測試來驗證之前完成的程式碼是否正確,而不需要反覆通過編譯執行simulator、等待應用啟動、通過輸入資料等繁瑣的步驟來驗證所完成的功能。用單元測試程式碼來驗證程式碼和通過釋出應用以人工的方式來驗證程式碼這兩者的效率差很多,所以單元測試其實還能節約人力成本。

3.她的存在讓你輕鬆愉快。保證你最後的程式碼修改不會破壞之前程式碼的功能。
專案越做越大,程式碼越來越多,特別涉及到一些公用介面之類的程式碼或是底層的基礎庫,誰也不敢保證這次修改的程式碼不會破壞之前的功能,所以與此相關的需求會被擱置或推遲,由於不敢改進程式碼,程式碼也變得越來越難以維護,質量也越來越差。而單元測試就是解決這種問題的很好方法(不敢說最好的)。由於程式碼的歷史功能都有相應的單元測試保證,修改了某些程式碼以後,通過執行相關的單元測試就可以驗證出新調整的功能是否有影響到之前的功能。當然要實現到這種程度需要很大的付出,不但要能夠達到比較高的測試覆蓋率,而且單元測試程式碼的編寫質量也要有保證。

4.她能為你排憂解難,永遠做你的依靠。讓你的程式碼維護更容易。
由於給程式碼寫很多單元測試,相當於給程式碼加上了規格說明書,開發人員通過讀單元測試程式碼也能夠幫助開發人員理解現有程式碼。比如開源專案(如AFNetworking, FMDB,喵神的VVDoucment等)都有相當量的單元測試程式碼,通過讀這些測試程式碼會有助於理解生產原始碼。

5.她甘心做你堅強的後盾,在你賣命打拼時無後顧之憂。她有助於改進程式碼質量和設計。
除了那些大拿們編寫的程式碼,我相信很多易於維護、設計良好的程式碼都是通過不斷的重構才得到的。雖然說單元測試本身不能直接改進生產程式碼的質量,但它為生產程式碼提供了“安全網”,讓開發人員可以勇敢地改進程式碼,從而讓程式碼的clean和beautiful不再是夢想。

說了那麼多,其實就是想表明基於測試驅動的開發,對你來說就達到了事半功倍的目的。

具體例子可以看看官網的Demo或者Google下了。https://developer.apple.com/library/content/samplecode/UnitTests/Introduction/Intro.html

Test 斷言

XCTFail(format…) 生成一個失敗的測試;

XCTAssertNil(a1, format...)為空判斷,a1為空時通過,反之不通過;

XCTAssertNotNil(a1, format…)不為空判斷,a1不為空時通過,反之不通過;

XCTAssert(expression, format...)當expression求值為TRUE時通過;

XCTAssertTrue(expression, format...)當expression求值為TRUE時通過;

XCTAssertFalse(expression, format...)當expression求值為False時通過;

XCTAssertEqualObjects(a1, a2, format...)判斷相等,[a1 isEqual:a2]值為TRUE時通過,其中一個不為空時,不通過;

XCTAssertNotEqualObjects(a1, a2, format...)判斷不等,[a1 isEqual:a2]值為False時通過;

XCTAssertEqual(a1, a2, format...)判斷相等(當a1和a2是 C語言標量、結構體或聯合體時使用,實際測試發現NSString也可以);

XCTAssertNotEqual(a1, a2, format...)判斷不等(當a1和a2是 C語言標量、結構體或聯合體時使用);

XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)判斷相等,(double或float型別)提供一個誤差範圍,當在誤差範圍(+/-accuracy)以內相等時通過測試;

XCTAssertNotEqualWithAccuracy(a1, a2, accuracy, format...) 判斷不等,(double或float型別)提供一個誤差範圍,當在誤差範圍以內不等時通過測試;

XCTAssertThrows(expression, format...)異常測試,當expression發生異常時通過;反之不通過;(很變態) XCTAssertThrowsSpecific(expression, specificException, format...) 異常測試,當expression發生specificException異常時通過;反之發生其他異常或不發生異常均不通過;

XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...)異常測試,當expression發生具體異常、具體異常名稱的異常時通過測試,反之不通過;

XCTAssertNoThrow(expression, format…)異常測試,當expression沒有發生異常時通過測試;

XCTAssertNoThrowSpecific(expression, specificException, format...)異常測試,當expression沒有發生具體異常、具體異常名稱的異常時通過測試,反之不通過;

XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...)異常測試,當expression沒有發生具體異常、具體異常名稱的異常時通過測試,反之不通過。

特別注意下XCTAssertEqualObjects和XCTAssertEqual。
XCTAssertEqualObjects(a1, a2, format...)的判斷條件是[a1 isEqual:a2]是否返回一個YES。XCTAssertEqual(a1, a2, format...)的判斷條件是a1 == a2是否返回一個YES。對於後者,如果a1和a2都是基本資料型別變數,那麼只有a1 == a2才會返回YES。

相關文章