在專案中寫了單元測試後,接下來一般就是要透過「程式碼覆蓋率」(Code Coverage)這個指標、來確認自己的測試程式寫得是否夠完整了。
而在 Visual Studio 或 GitLab 上,都有針對這部分有一定程度的支援,可以方便使用者確認自己的測試程式覆蓋狀態。
不過比較可惜的,是 Visual Studio 要到更為昂貴的企業版才有內建這樣的功能(官方文件);而非企業版的用戶,則是需要透過延伸模組、找第三方的方案(例如 Fine Code coverage)來使用了。
而在 GitLab 上則可以透過 GitLab CI/CD 來產生覆蓋率報告,而且這項功能目前是免費版也可以使用的,官方的文件可以參考《Test coverage visualization》;不過相對地它的顯示方式較為受限,如果沒有真的使用 GitLab Flow、而是只把 GitLab 拿來做版本控管的話,基本上很難看到他的報告。
總之,這篇就簡單講一下在這兩種環境下,要怎麼去產生程式碼覆蓋率的報告、並怎麼看程式碼的被覆蓋到。
這邊使用的範例,可以參考 Heresy 放在 GitLab 上的專案的「coverage」這個分支(連結)。
Visual Studio 企業版
在 Visual Studio 企業版,在「測試總管」中,只要選取要進行的測試、然後在滑鼠的右鍵選單裡就可以找到「分析程式碼涵蓋範圍」的選項了。
點選這個選項後,他就會去執行選取的測試、並進行程式碼覆蓋率的分析;結束後,會開啟「程式碼涵蓋範圍結果」的視窗、並可以選取產生過的報告(附檔名是 .coverage
)。
下面就是一份簡單的報告。他會透過 namespace 等東西做分群、後面要顯示的欄位可以自行設定。
可以看到,這邊一個比較大的問題,是他預設也會把有用到的第三方函示庫拉進來分析;這邊由於使用了 Boost Test,所以就變成滿滿的 boost 了…
也因此,直接這樣跑的話,整體的覆蓋率其實不太可能拉高、意義也不大;真的要用的話,就得找到自己的程式的部分,來確認這些區域的覆蓋率了。
而在個人來看,Visual Studio 這項功能比較實用的,是他可以在產生報告後,透過開啟工具列上的「顯示程式碼涵蓋範圍著色」的選項,來在程式碼編輯器裡面直接透過顏色告訴開發者,哪邊經過測試哪邊沒有!
這邊在開啟後,程式碼編輯器就會變成像是下面的狀況:
藍色的部分是有涵蓋、也就是有測試過而橘色的部分則是未涵蓋,代表都沒測試到;而黃色的部分,則是代表僅有部分涵蓋。
透過這樣的顯示,就可以很清楚地看的出來,目前的測試還缺少那些東西了!
而如果不是企業版的話,目前是知道「Fine Code coverage」這個延伸模組可以提供一定程度的涵蓋範圍的功能。
不過比較可惜的,是他雖然有支援 C++ 的專案,但是沒辦法處理 C++ Template 的部分;所以如果 template 用的比較多的話,其實就沒什麼用了。
GitLab 的覆蓋率顯示
GitLab 提供的 Code Coverage 的功能在 Heresy 來看算是比較弱了一點,主要顯示的結果有兩種:
-
- 顯示覆蓋率(單一數值、百分比)
- 在 Merge Request
裡面的程式碼差異比較的時候,會顯示變化的程式碼是否有被測試涵蓋到。
而要有這兩項結果,也都是需要在 GitLab CI/CD 裡面建立對應的工作、並讓他去產生需樣的資訊的。
其中,第一個就是透過單一個百分比來代表整體的覆蓋率的顯示方式;這個數值會在專案的 CI/CD 的 jobs 中看到(實際頁面),像這邊就是 79.4%。
而除了在 jobs 中顯示外,也可以透過專案的「badges」系統(官方文件),加到專案的首頁,讓使用者更快地看到最新的數值:
不過這邊比較可惜的,是 badges 是針對專案做設定的,所以沒辦法針對不同分支顯示不同的狀態。
另外,在專案的 Analytics 的 Repository 中,也可以看到一段時間內的 code coverage 數值的變化。
至於第二項顯示那些程式碼有被涵蓋、在 Heresy 來看應該是比較重要的,但是 GitLab 應該沒辦法在一般看、或是編輯程式碼的時候就看到覆蓋狀況,而是只能在 merge request 裡才會顯示(頁面):
這樣設計主要的目的,應該是讓管理者在接受 merge request 的時候,是可以確認要 merge 的程式碼是否有經過測試、避免沒有經過測試的程式進入程式庫中。
不過,以 Heresy 這邊工作環境基本上沒有在用 merge request 的狀況來說,要能看到程式碼是否有被涵蓋的機率…恩,好像低到不行啊。 XD
GitLab 產生覆蓋率
回過頭來,要怎麼針對 C++ 專案來輸出 code- coverage 的資料給 GitLab 呢?在官方的 C/C++ example(連結)中,就有提供了一個 .gitlab-ci.yml 的範例工作,來說明該怎麼進行了;它的內容如下:
run tests: stage: test script: - cd build - make test - gcovr --xml-pretty --exclude-unreachable-branches --print-summary -o coverage.xml --root ${CI_PROJECT_DIR} coverage: /^\s*lines:\s*\d+.\d+\%/ artifacts: name: ${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}-${CI_COMMIT_SHA} expire_in: 2 days reports: coverage_report: coverage_format: cobertura path: build/coverage.xml
他的範例是 Linux 環境下,使用 make 系統的範例;而這邊也可以看到,這邊基本上是透過「gcovr」這個套件(官方文件),來計算程式碼覆蓋範圍、並產生出符合 Cobertura XML 格式標準的報告。
而實際上,這邊回報給 GitLab 的有兩個部分。
第一部分是「coverage
」的部分(官方文件),這邊是透過後面的正規表示式去分析這個工作中執行 gcovr 的 std out 輸出的結果,找出符合需求的字串裡的數字、作為整體的覆蓋率數值:
coverage: /^\s*lines:\s*\d+.\d+\%/
其中會被拿來用的是 \d+.\d+
抓出來的浮點數。
實際上,gcovr 輸出的彙整結果中,覆蓋率有三種算法:
lines: 79.4% (27 out of 34) functions: 83.3% (10 out of 12) branches: 50.0% (118 out of 236)
不想用行數作為計算標準的話,也可以自己修改判斷式。
至於第二個部分,則是完整的覆蓋範圍報告、也就是 artifacts
的部分;這邊需要的是 Cobertura coverage 的檔案格式(官方文件);要有這份報告,才能在介面中顯示那些程式有被覆蓋到。
gcovr 的使用
在他的範例裡,在執行腳本的部分,他會先透過「make test」、建置專案、並執行所有測試;等到都執行完後,才是透過 gcovr 來彙整所有資料、並產生出「coverage.xml」這個彙整過的報告檔案。
但是實際上,並不是直接這樣跑就可以了。除了要在 Makefile
裡面有對應的 test
腳本外,要使用 gcovr 的話,實際上是還需要修改編譯參數,在建置的時候讓他產生對應的檔案,他才有辦法分析的。
這邊要使用的參數是:
- 編譯參數:-fprofile-arcs -ftest-coverage -fPIC -O0
- 連結參數:-lgcov –coverage
如此一來,在編譯的時候,他會產生許多 .gcno 的檔案;而之後執行測試程式的時候,他則會另外產生 .gcda 的檔案、記錄程式執行時的狀態報告。
在這些檔案正確產生之後,則還需要透過 gcovr 來分析這些產生出來的檔案、產生彙整的報告了。
不過由於這邊需要加特別的參數來建置才行,所以如果整個 CI/CD pipeline 還需要本來的建置、測試流程的話,應該會需要有比較好的機制、來切換 Makefile 裡面的建置、連結的參數了;畢竟,-O0
這種參數並不適合用來作為最終的輸出啊~
Visual Studio
如果是要針對 Windows 平台、以腳本的形式來讓 Visual Studio 來產生對應的報告文件…恩,感覺好像有點麻煩,個人目前還沒找到好方法。
目前看到可能可行的方法,似乎是先透過 vstest.console.exe
來跑測試,然後透過 Dynamic Code Coverage Tools\CodeCoverage.exe
來轉換格式後,再透過 ReportGenerator
這種工具來轉換成 Cobertura XML 格式的報告。(參考)
但是如果是要掛在 GitLab CI/CD 的runner 上用 Docker 來執行的話,用 Visual Studio Build Tools 建置的 Docker image 裡面似乎都沒包含需要的工具…
再加上 GitLab 的網頁介面主要也只能對應一組覆蓋率,而且顯示覆蓋範圍的功能目前看來實用度不高,所以現階段個人是跳過這部份了。
這篇大概就是這樣了。
基本上,這邊只是整理一下玩出來的東西,稍微做個分享;實際上,這邊的方法可能也不是最好的。
而以目前的經驗來看,個人是覺得 GitLab 在這方面提供的使用者介面,包含 code coverage 在內、很多報告都還是侷限在 merge request 才能用,這點對於沒有在用 merge request 的小專案來說,其實算是滿不方便的。
實務上,Heresy 這邊在 Gitlab 上的 code coverage 好像就只剩下看覆蓋率的功能了…真正要確認有沒有被覆蓋、哪邊沒被覆蓋,還是得回到 Visual Studio 去看。
個人是還滿希望 GitLab 以後可以針對這部分再做強化。