全國服務熱線0313-2562332 在線咨詢 留言/需求提交

實戰iOS 9:詳解Xcode的Code Coverage工具

【摘要】?iOS9 Day-by-Day是作者Chris Grant寫的系列博客,覆蓋了iOS開發者必須知道的關于iOS 9的新技術與API,并且還進行了實際操作演練。本文詳細介紹了Xcode中計算單元測試覆蓋率的Code Coverage工具。

iOS9 Day-by-Day是作者Chris Grant寫的系列博客,覆蓋了iOS開發者必須知道的關于iOS 9的新技術與API,并且還進行了實際操作演練,每篇文章中相關的代碼Chris都會將其上傳至GitHub上,在Search APIs、UI Testing、Storyboard References、UIStackView之后,作者寫到了第五篇——Xcode Code Coverage。譯文如下:

Code coverage是一個計算你的單元測試覆蓋率的工具。高水平的覆蓋給你的單元測試帶來信心,也表明你的應用被徹底的測試過了。你可能寫了幾千個單元測試,但如果覆蓋率不高,那么你寫的這套測試可能價值也不大。

這里并沒有一個確切的百分比,要求你必須到達這個覆蓋率。這很大程度上取決于你的項目(的具體情況)。譬如說,如果你的項目中有很多不能寫單元測試的視覺組件,那么覆蓋率就會比單純處理數據的框架要低的多。

Code Coverage in Xcode

在過去,如果你想要制作一個測試的代碼覆蓋報告出來,需要設置很多[選項]。非常復雜,還有許多需要手動設置。在iOS 9中,蘋果提供了智能的代碼覆蓋工具,它是和LLVM一體的,每次運行測試都會被調用和計算。

Using the Code Coverage Tools

現在我們用一個例子來展示,如何使用新的code coverage工具和怎樣提升現在的測試用例。完成后的代碼放在了Github上,你可以跟著做。

第一件事是創建一個新項目,并確認你選上了Unit tests選項。這會按要求創建一個默認項目,現我們需要測試點什么。這個測試可能是你的任意需求,這里我添加一個空的swift文件,里面寫好了一個全局的方法。這個方法檢測兩個字母串是否是僅排序不同的相同字母組成的詞。寫成全局的方法,可能不是好的設計,但這里我們僅演示一下。

這是一個相對簡單的方法,所以我們可能會得到一個沒有任何問題的,100%覆蓋的測試覆蓋率。


[cpp] view plaincopy

  1. func checkWord(word: String, isAnagramOfWord: String) -> Bool {  

  2.     // Strip the whitespace and make both of the strings lowercase  

  3.     let noWhitespaceOriginalString = word.stringByReplacingOccurrencesOfString(" ", withString: "").lowercaseString  

  4.     let noWhitespaceComparisonString = isAnagramOfWord.stringByReplacingOccurrencesOfString(" ", withString: "").lowercaseString  

  5.     // If they have different lengths, they are definitely not anagrams  

  6.     if noWhitespaceOriginalString.characters.count != noWhitespaceComparisonString.characters.count {  

  7.         return false  

  8.     }  

  9.     // If the strings are the same, they must be anagrams of each other!  

  10.     if noWhitespaceOriginalString == noWhitespaceComparisonString {  

  11.         return true  

  12.     }  

  13.     // If they have no content, default to true.  

  14.     if noWhitespaceOriginalString.characters.count == 0 {  

  15.         return true  

  16.     }  

  17.     var dict = [Character: Int]()  

  18.     // Go through every character in the original string.  

  19.     for index in 1...noWhitespaceOriginalString.characters.count {  

  20.         // Find the index of the character at position i, then store the character.  

  21.         let originalWordIndex = advance(noWhitespaceOriginalString.startIndex, index - 1)  

  22.         let originalWordCharacter = noWhitespaceOriginalString[originalWordIndex]  

  23.         // Do the same as above for the compared word.  

  24.         let comparedWordIndex = advance(noWhitespaceComparisonString.startIndex, index - 1)  

  25.         let comparedWordCharacter = noWhitespaceComparisonString[comparedWordIndex]  

  26.         // Increment the value in the dictionary for the original word character. If it doesn't exist, set it to 0 first.  

  27.         dict[originalWordCharacter] = (dict[originalWordCharacter] ?? 0) + 1  

  28.         // Do the same for the compared word character, but this time decrement instead of increment.  

  29.         dict[comparedWordCharacter] = (dict[comparedWordCharacter] ?? 0) - 1  

  30.     }  

  31.     // Loop through the entire dictionary. If there's a value that isn't 0, the strings aren't anagrams.  

  32.     for key in dict.keys {  

  33.         if (dict[key] != 0) {  

  34.             return false  

  35.         }  

  36.     }  

  37.     // Everything in the dictionary must have been 0, so the strings are balanced.  

  38.     return true  

  39. }  


一旦你寫好了算法,就該寫個測試了。打開項目創建時已經創建好了的默認的XCTestCase,添加一個下面的簡單的測試方法。他看起來是這樣子的。


[cpp] view plaincopy

  1. class CodeCoverageTests: XCTestCase {  

  2.     func testEqualOneCharacterString() {  

  3.         XCTAssert(checkWord("1", isAnagramOfWord: "1"))  

  4.     }  

  5. }  


在運行測試之前,我們必須先確認code coverage是否被打開了,寫代碼時,默認是關閉的。所以你需要編輯一下你的測試scheme,把它打開。


確保"Gather coverage data"是被選中的,然后點擊關閉按鈕,運行測試的 target. 我們希望剛剛創建的測試用例能夠順利通過。

The Coverage Tab

一旦這個測試通過了,你就能知道checkWord這個方法,至少有一條路徑是對的。但你不知道的是,還多多少沒有被測試到。這就是code coverage這個工具的好處。當你打開code    coverage tab后,你可以清楚的看到測試的覆蓋情況。他們按找target、file、function進行了自動分組。

打開Xcode左邊窗口的Report Navigator面板,選中你剛運行的測試。然后在tab中選中Coverage。


這會展示一個你的類、方法的列表,并標示出每個的測試覆蓋率。如果你將鼠標懸停在checkWord這個方法上,你可以看到測試的覆蓋率是28%。 不能接受啊!我們需要找到,那些代碼分支是能夠被測試執行,那些是不能的,進而改善他們。雙擊方法的名字,Xcode會打開類的代碼,并且看到code    coverage的情況。


白色的區域表示這些代碼時測試覆蓋過的。灰色區域時測試無法覆蓋的,我們需要添加更多的測試用例來覆蓋灰色部分的代碼。在右手邊的數字,表明這些代碼塊,在這次測試中被執行的次數。

Improving Coverage

很顯然,28%的覆蓋率不是我們的目標。這里沒有UI,看起來是個完美的編寫測試用例的候選function。所以,我們添加一個測試用例。理想情況下,我們希望每個分支都能被測試到。這樣就能達到完整的覆蓋。添加下面的測試用例到你的測試類中。


[cpp] view plaincopy

  1. func testDifferentLengthStrings() {  

  2.     XCTAssertFalse(checkWord("a", isAnagramOfWord: "bb"))  

  3. }  

  4. func testEmptyStrings() {  

  5.     XCTAssert(checkWord("", isAnagramOfWord: ""))  

  6. }  

  7. func testLongAnagram() {  

  8.     XCTAssert(checkWord("chris grant", isAnagramOfWord: "char string"))  

  9. }  

  10. func testLongInvalidAnagramWithEqualLengths() {  

  11.     XCTAssertFalse(checkWord("apple", isAnagramOfWord: "tests"))  

  12. }  


這些測試用例應該能夠完全覆蓋我們的代碼了。運行一下單元,然后打開最后一個測試報告。


我們成功了,100%的覆蓋率。你可以看到整個代碼都變成了白色,右面的數字也展示了每個代碼段至少被執行了一次。

使用code coverage是一個非常棒的方式,幫你建立真正有價值的測試組合。遠好于你寫了很多測試用例,但沒有真正測試到代碼。Xcode    7 讓這種方式變的非常簡單,我推薦你在項目中開啟 Code Coverage。即使你已經寫好了測試,也可以幫你知道到底測試寫的怎么樣。

延伸閱讀

更多關于Xcode 7中Code Coverage工具的內容,我推薦你觀看WWDC 2015 的session 410 Continuous Integration and Code Coverage in Xcode。最后,別忘了如果你想要試試我們上面的例子,可以在Github中找到它。


聲明: 文章為張家口易誠網絡科技有限公司原創文章,轉載請注明出處,謝謝合作!

文章閱讀推薦

文章排行

2019年以太坊走势分析 重庆时时真的存在吗 广东时时开奖结果走势图 3号彩票网app 云南时时下载手机版 快乐彩怎么玩才赚钱 天津快乐十分遗漏走势图 不限ip多账号送彩金 重庆时时诈骗最新案 三期必出特一白小姐开奖结果 极速时时三码一期计划 体彩:排三试机号 青海快3走势图 福建时时倍投技巧 金年王中王一肖中特 推荐几个好文章公众号 五大联赛开赛日期