「既然都設定好覆蓋率報表了,為什麼 CI 上還要特地加一個參數把它關掉?」
這是這個套件最反直覺的地方:phpunit.xml 裡對覆蓋率報表的設定寫得很完整,但 CI 執行測試時,卻用一個參數把它整個關掉。今天就把這個矛盾拆開來看。
phpunit.xml 裡覆蓋率報表的設定內容phpunit.xml 裡寫的覆蓋率設定<coverage>
<include>
<directory suffix=".php">src</directory>
</include>
<report>
<clover outputFile="build/logs/clover.xml"/>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
</report>
</coverage>
這段設定告訴 PHPUnit:只計算 src/ 目錄的覆蓋率(測試檔案自己不算),輸出三種格式的報表——clover(給 CI 平台如 Codecov、Scrutinizer 讀的機器格式)、HTML(人可以點開來看每一行有沒有被測到)、純文字(快速在終端機看摘要)。
看起來像是一套認真規劃過的覆蓋率追蹤機制。
.github/workflows/tests.yml 裡真正執行測試的那一步是:
- name: Execute tests
run: vendor/bin/phpunit --testdox --no-coverage
--no-coverage 這個參數告訴 PHPUnit:這次執行不要收集覆蓋率資料,不管 phpunit.xml 裡設定了什麼報表格式,這次都不會產生。也就是說,phpunit.xml 裡那段設定,目前只有在本機手動下指令、而且沒加 --no-coverage 時才會真的發生作用;在 CI 這個「理論上應該持續追蹤品質趨勢」的地方,它其實從未被執行過。
這個套件的維護紀錄裡沒有明講「為什麼 CI 用 --no-coverage」,只能推測。但有一件事是可以實際驗證的:要讓覆蓋率報表真的跑起來,本身就有額外的技術門檻。
我在一份本機的暫存複本上實際測試過:直接執行 vendor/bin/phpunit --coverage-text,PHPUnit 給出的結果是:
There was 1 PHPUnit test runner warning:
1) No code coverage driver available
OK, but there were issues!
意思是本機的 PHP 環境沒有裝 pcov 或 Xdebug 這類覆蓋率驅動,PHPUnit 根本無法產生覆蓋率數字。我接著嘗試用 pecl install pcov 補裝,結果編譯過程中因為系統缺少 pcre2.h 這個底層依賴而失敗。
這不是在說這個套件的維護者當初就是因為裝不起來才放棄——我沒有證據能證明這是真正的原因,這只是我自己在另一個環境上重現時撞到的真實狀況。但它足以說明一件事:「幫 CI 開啟覆蓋率」不是加一個參數就結束,背後牽涉到「CI 執行環境有沒有裝對覆蓋率驅動」這個常常被低估的前置成本。這也是一個合理的推測:對很多專案來說,--no-coverage 是圖方便的選擇,不一定是「不重視覆蓋率」,可能只是「權衡之下,先讓測試能穩定跑過比較重要」。
❌ 看起來有覆蓋率把關,實際上沒有
# phpunit.xml 設定了完整的 coverage 報表
# CI 卻執行:
run: vendor/bin/phpunit --testdox --no-coverage
# 結果:沒有人知道現在的覆蓋率是多少,PR review 時也看不到覆蓋率變化
✅ 覆蓋率設定跟 CI 執行方式一致
# CI 安裝好 pcov 之後執行:
run: |
vendor/bin/phpunit --coverage-clover build/logs/clover.xml
# 額外接一步上傳到 Codecov 或在 PR 留言顯示覆蓋率變化
正例不是這篇文章的重點在教你怎麼設定 CI(那部分等第四部動手做的時候再細講),這裡想強調的是:光是把 <coverage> 區塊寫進 phpunit.xml,不會讓覆蓋率自動被守住——它只是定義了「如果有人去跑,會產生什麼格式的報表」,真正決定「這次測試有沒有被拿來檢查覆蓋率」的,是執行指令裡有沒有那個 --no-coverage。
覆蓋率報表這個問題,這個系列後面還會回來處理兩次:
你的專案 CI 裡有沒有類似的落差——設定檔裡寫了一套機制,但實際執行指令卻加了參數把它繞過去?你知道加那個參數的原因是什麼,還是也只是「一直都這樣」?
phpunit.xml 定義了完整的覆蓋率報表輸出格式,但只在沒加 --no-coverage 時才會真正產生--no-coverage,覆蓋率報表從未在 CI 上真的被產出過第一部到這裡告一段落。明天進入第二部,會拆開一筆真實的 commit(80d3469),看看在沒有覆蓋率門檻推著走的情況下,測試實際上是怎麼被補上的。