重構的時候咱們須要一個模具,讓咱們可以大膽修改的同時確保結果的正確性,這個時候就要引入「單元測試」了。xcode
本文沒有給出任何測試代碼,或者是在教你如何編寫一份具備良好測試性的代碼,而是闡述在重構過程當中單元測試的重要性與實現方法,關於代碼可測試性相關的內容我會另開一篇文章去具體闡述。(畫個餅)網絡
在開發過程當中咱們會遇到這樣一些問題:app
另外咱們也許還會遇到一些這樣的模塊:框架
這個時候也許可以利用經驗和豐富的debug技巧來解決這些問題,可是不少時候咱們的處理並不完美,由於咱們缺乏了一個規範,在編碼過程當中難以顧及其餘模塊的影響,這個時候,咱們就須要引入單元測試。異步
當在對代碼進行修改時,利用單元測試就可以清晰的知道是否破壞了老的業務邏輯,這樣大大減小了迴歸出錯的可能性。而當咱們從測試那裏得到了一個bug時,就能夠經過測試用例去還原,當咱們這個測試經過後,這個bug也就解決了,並且這個bug fix的測試用例也保證了這個bug之後不會再次出現。函數
有了單元測試的保障,咱們能夠比較大膽的進行重構設計,而單元測試也會成爲重構時很好的一個模具。固然在重構時也須要對單元測試進行重構,可是和可靠性相比,這種額外的負擔是值得去承受的性能
在調試中,咱們不少時候都須要花費一些額外的時間來觸發須要調試的代碼,可是在單元測試中,咱們可以針對須要調試的代碼構建相關的測試用例,方便的進行反覆的測試與模擬,大大減小了調試的時間。
測試的存在價值就是爲咱們發現並解決錯誤,單元測試更是如此,當咱們對本身的代碼進行單元測試時,就能容易的排除掉一些很是低級的錯誤,起碼咱們可以保證在一些正常的狀況下代碼是能夠正確工做的。
好的代碼就是一份好的文檔,單元測試更是如此。一份好的單元測試可以描述在對應的狀況下,代碼應該有如何的預期表現,那麼別人只須要查看測試用例就能清楚的知道代碼的功能。
一份代碼若是和其餘代碼強耦合,它是難以被測試的,因此爲了測試,開發人員會被驅使寫出低耦合、可擴展的代碼。
單元測試中有測試驅動開發(TDD)與行爲驅動開發(BDD)兩種思路
基於目前項目的狀況與開發流程,我選擇了BDD做爲測試框架,並會選擇使用XCTest + OCMock + OCHamcrest的方案,如下是三個框架的介紹:
mock即爲模擬,OCMock能夠僞造(模擬)一個對象,給它一些預設的值之類的,並進行對應的驗證
好比在我須要測試WiFi直連模塊時,我須要一個WiFi才能測試直連功能,這個時候咱們就能夠利用OCMock,去模擬一個WiFi對象,它能夠是模擬成風險WiFi,也能夠模擬成免費WiFi,這樣咱們的直連模塊的測試就徹底獨立於WiFi對象,能夠方便的進行測試。
在寫任何測試前,應該明確應該要測試什麼,通常的狀況下,單元測試應該包括這些內容:
針對目前項目狀況,我會使用單元測試與人工測試相結合的方式去進行,由於目前咱們大部分功能都是與UI牽連,不能徹底依靠單元測試去完成全部的測試工做,可是咱們能夠將邏輯部分進行分離,舉網絡鏈接模塊爲例:
請求流程
咱們能夠對界面相關的部分測試進行拆解,在邏輯部分實現單元測試,而人工測試部分單純檢查整個直連流程和界面部分是否正常。
這樣可以避免人工測試時依賴於邏輯的狀況,好比在須要測試發起100個請求後模塊是否會出現問題時,無需依靠手工去真的鏈接100次,只須要在單元測試中模擬進行100次鏈接,並查看結果是否正確就能夠。
在項目中,咱們有大量的類,所有覆蓋單元測試是不現實的,咱們須要進行挑選。如下是我列舉的一些因素。
好比在本地數據存儲模塊中,咱們須要保存不一樣的數據,這時候咱們能夠經過單元測試構造不一樣的測試數據進行保存,查看是否保存成功,數據部分是單元測試最須要覆蓋的部分。
好比在鏈接模塊中,須要對部分請求結果進行過濾,這就是一個邏輯,針對這種邏輯,能夠在單元測試中進行測試是否過濾成功,而人工測試則無需關注過濾的邏輯,僅僅須要關注過濾後界面是否正常顯示。
好比在鏈接模塊中,鏈接的狀態就有8種,包括了連通性檢查、鏈接中、已鏈接等,這些狀態可以利用單元測試很好的模擬出來,這樣就解決了人工測試下難以模擬不一樣狀態轉換的問題。
咱們寫代碼最終的目的只有兩個:實現需求與提升代碼質量,在保證完成需求的前提下,增長單元測試能提升代碼的質量與可維護性,縱使在引入了單元測試後,咱們也許會面臨增長了研發的代碼量,花費更多精力在編寫單元測試上,增長了開發成本,但我認爲相比於單元測試帶來的優點,這些是可以克服的。
更多內容能夠關注個人博客