本文是投稿文章,作者:2bcat(博客)
一、前言
由於蘋果開發的封閉性,一直以來都沒有良好的測試驅動開發支持。懷抱在iOS開發中實現TDD持續集成的工程師們為此提供了許多三方庫以達到與Android開發同等的TDD支持,然而由於其學習成本高,普及性始終不夠廣泛,致使大部分iOS開發工程師形成了APP開發無需單元測試或UI自動化測試的錯誤認識。
直至XCTest替代OCUnit,並提供了異步測試、性能測試等新特性,單元測試的使用者越來越多。XCode7提供了UI Testing以替代Instrument中的Automation測試,真正使TDD在iOS開發中走上了康莊大道。
Unit Test中可以直接訪問目標Target的代碼,因此對代碼覆蓋率的支持一直是良好的。
然而如何在UI Testing中支持代碼覆蓋率,以及增強代碼覆蓋率的可讀性,在APP中獲得接入SDK的代碼覆蓋率等問題,筆者在Forum.developer.com、StackOverflow、Google等各方搜索,均只看到提問,而沒有答案。一方面固然是iOS開發者對TDD的不重視、不習慣,另一方面也是由於蘋果官方對這些問題沒有明確的答案。
經過摸索與驗證,特別將解決方案分享給有需要的朋友們。
二、UI Testing的單元測試編寫方法
之前已經有文章講述過,再此不做重述,提供傳送門
1. 國外的一篇文章 UI Testing in Xcode 7, Part 1: UI Testing Gotchas
2. 喵神的 WWDC15 Session筆記 - Xcode 7 UI 測試初窺
三、解決前言中提到的幾個問題
1. UI Testing 中代碼覆蓋率的支持
查看Xcode各版本發布紀要
Known Issues in Xcode 7 beta — IDE
Xcode does not show code coverage information for source files in static libraries. (15605406)
Workaround: Add the source files directly to application or framework targets.
Code coverage does not work with UI testing. (20966994)
Resolved in Xcode 7 beta 4 - IDE
Code coverage works with UI testing(20966994)
Resolved in Xcode 7 beta 5 - IDE
Code Coverage now supports files in static libraries. The source files show up under each binary that links the static library in the Coverage tab of the Test Report. The source editor shows coverage numbers aggregated across all binaries.(21984681)
從發布紀要可以得知,目前Xcode中UI Testing對代碼覆蓋率的兼容,以及獲取靜態庫的代碼覆蓋率都有明確的支持。然而,在Xcode7.0-7.2的嘗試中,UI Testing始終得不到代碼覆蓋率,才深度研究了如下的解決方法。!!!然而在最新的Xcode 7.3beta中,發現不添加如下代碼也能夠看到UI Testing的代碼覆蓋率了!!!,白費了那麼久的搗騰啊。不過,如果你的XCode未能在UI Testing 中給出代碼覆蓋率。嘗試在main.m中加入如下代碼:
#import #import "AppDelegate.h" dispatch_source_t SIGTERMHandlerSource; int main(int argc, char * argv[]) { @autoreleasepool { signal(SIGTERM, SIG_IGN); SIGTERMHandlerSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_SIGNAL, SIGTERM, 0, dispatch_get_main_queue()); dispatch_source_set_event_handler(SIGTERMHandlerSource, ^{ exit(0); }); dispatch_resume(SIGTERMHandlerSource); return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } }
這裡代碼的主要意義是使系統不去處理 SIGTERM 信號,而自行提供處理方法。修改main.m文件之後,在跑UI自動化測試時就可以看到代碼覆蓋率了!
Code Coverage的基本設置圖如下,更改Scheme的Test中的勾選項,把 Gather coverage data 勾上,然後就可以Command+U或者指定某個UI自動化用例執行了。另外,在Scheme的編輯中,可以指定Test時需要測試哪些單元測試,具體見圖:
2.如何獲得靜態包的代碼覆蓋率?
接入APP是不能直接訪問靜態庫工程的文件的,因此接入APP的UI測試得不到靜態庫工程的代碼覆蓋率,如何解決呢?很簡單,雖然靜態包不能單獨運行UI,但可以在靜態庫的Scheme-Test中添加接入APP的測試Target,就可以在靜態庫的project裡用看到UI Testing的用例並執行。測試類也可以直接訪問到靜態庫工程中的文件,並得到代碼覆蓋率結果了。同樣,這裡也需要勾選上 Gather coverage data, 如下圖:
再看我們得到的代碼覆蓋率結果,鼠標懸浮在藍條時會有數值,點擊箭頭能進到文件看方法的執行次數。如圖:
結果是得到了,但每次都要懸浮到藍條上看數值,以及得不到整體統計,可讀性非常差。
3.如何使代碼覆蓋率測試結果增強可讀性?
測試結果文件的位置,從工程目錄的生成app,打開finder,往上找Intermediates文件夾就行了。Coverage.profdata就是我們要找的結果文件。
XCode代碼測試結果使用了LLVM Code Coverage Mapping Format, 具體格式介紹參考http://llvm.org/docs/CoverageMappingFormat.html。只要是標准格式,就可以按想要的方式解讀。這時llvm-cov上場了,llvm是隨Xcode一起安裝的,不需要另外安裝。如果遇到解析文件報錯LLVM版本不對的,可以用Xcode-select --print-path看下生成文件時的Xcode路徑和跑用例時用的Xcode是不是一個,如果不是,重新選擇。
解析文件的命令為xxx/llvm-conv report -instr-profile xxx/Coverage.profdata xxx/xx.app/xx,其中report為參數,可以換成show得到各文件結果。xx.app要取與Coverage.profdata同目錄的Products文件夾內的。
這時,我們可以直觀的得到各個文件的代碼覆蓋率數值信息,這裡帶入了雜質信息,真機和模擬器均存在。但是,這是無關緊要的。我們APP開發或SDK開發都會習慣添加類前綴,那麼通過使用shell腳本篩選我們需要的行,重新計算統計值,就能得到app部分文件或靜態庫文件的統計結果。