GitLab CI - 在 Pipeline 檢視 PHPUnit 單元測試報告

GitLab CI Report Demo

許多使用 GitLab 作為版本控制工具的使用者,要開始搭配 GitLab CI/CD 建立專案的持續整合流程時,一開始通常是從專案既有的測試開始著手,讓「測試」在每次原始碼 commit 後就自動執行,進而增加原始碼的品質。

在 GitLab 版本 11.2 之後,GitLab CI 開始提供了讓使用者可以簡便的在 Pipeline 中就看到 Pipeline 過程中產出的報表功能。其主要是透過 artifacts 夾帶 Pipeline 工作中產出的報表。

在 GitLab CI 提供的眾多報表功能中,artifacts:reports:junit 主要是用來搜集並呈現「單元測試」執行結果的報表,使用JUnit report format XML files,看到 JUnit 熟悉的朋友可能知道,這是 Java 語言在撰寫單元測試常用的工具。那麼,在 PHP 語言中,如果也要產出同樣的報表,應該要怎麼產生呢?

一、初探 artifacts:reports:junit

在 GitLab 的 artifacts:reports:junit文件中,提供了如下的 JUnit 報表範例:

1
2
3
4
5
6
7
8
rspec:
stage: test
script:
- bundle install
- rspec --format RspecJunitFormatter --out rspec.xml
artifacts:
reports:
junit: rspec.xml

在這段範例中,主要看兩段關鍵重點:

1
2
3
script:
- bundle install
- rspec --format RspecJunitFormatter --out rspec.xml

首先是 Script 的部分,這段範例中以 Ruby 的 rspce 為產出 JUnit 格式的展示,在 rspec 中,使用 --format 來宣告要輸出的報表格式,這邊使用 RspecJunitFormatter 也就是 artifacts:reports:junit 需要的 JUnit XML 格式,並透過 --out 設定要輸出的檔案格式為何,這邊使用 rspec.xml,因此執行後,會在本地端產出一個名稱為 rspec.xml 的檔案。

1
2
3
artifacts:
reports:
junit: rspec.xml

在 GitLab CI 中 artifacts 通常是用來搜集 GitLab CI Job (工作),所產出的產出物,在 artifacts:reports:junit 裡,即透過宣告為 reports 中的 junit 格式,來取得上一段 rspec 所產出的 rspec.xml 檔案,使其作為 JUnit 報表。

二、PHPUnit 產出 JUnit 報表格式

在這次的範例中,直接使用 composer 官方所提供的 docker image 作為執行環境,因此預設使用了 PHP 8.0。

1. GitLab CI 執行環境

2. 在 GitLab 共用的模板

1
2
3
4
5
6
.test_template:
stage: test
image: "composer"
before_script:
- export COMPOSER_ALLOW_XDEBUG=1
- composer install --prefer-dist > /dev/null

在底下的範例中,使用的模板都使用以上的共用安裝過程及共用的 docker image composer

三、在 GitLab CI 中執行 PHPUnit 並產出 JUnit XML 格式報表

1. 在 PHPUnit Command Line 執行指令中設定 JUnit XML Report 格式

在第一段中有提到要在 GitLab CI 的 Pipeline 顯示報表,最重要的是要在測試的過程中,產出 JUnit 格式的報表,在PHPUnit 官方手冊 中,提到如果要產出 JUnit 格式的紀錄,可以在執行 PHPUnit 的過程中加上 --log-junit <file>,那麼,在 GitLab CI 的 Pipeline 設定中,要怎麼設定呢?

1
2
3
4
5
6
7
test:phpunit-with-command-line:
extends: .test_template
script:
- php vendor/bin/phpunit --log-junit build/junit.xml
artifacts:
reports:
junit: build/junit.xml

如上原始碼,在 script 的區段中,使用 --log-junit <file> 語法,使其產出 JUnit 格式的報表到檔案路徑 build/junit.xml,接著透過 artifacts:reports:junit 語法,直接取得產出物 build/junit.xml 作為報表。執行後,可以在 Pipeline 中看到 Tests 的內容已經有一些數字呈現,點入後可以看到直接顯示在這個測試中有多少執行錯誤、跳過及通過等資訊:

GitLab CI Report Demo

點入後,可以在看到更詳細的內容描述,如每個測試案例的執行狀況、細節等:

Pipeline Test Report Detail

2. 在 PHPUnit 的 phpunit.xml 中設定 JUnit XML Report 格式

一般在使用 PHPUnit 的時候,會把常常需要使用的指令透過 phpunit.xmlphpunit.xml.dist 作為設定值,這樣每次在執行 PHPUnit 的時候,只要直接執行 php vendor/bin/phpunit 而不用再透過指令參數做設定。那麼在 phpunix.xml 中,要怎麼設定 JUnit 格式的報表呢?

PHPUnit 的手冊中關於 XML 設定檔的部分有提到,可以透過 <junit> 及其參數 outputFile 來做設定。如底下的範例:

1
2
3
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>

上面的原始碼宣告將 JUnit 格式的檔案輸出到 build/report.junit.xml 這個檔案路徑。因此對應的 GitLab CI Pipeline 描述,也只需要如底下原始碼:

1
2
3
4
5
6
7
test:phpunit-with-phpunit-file:
extends: .test_template
script:
- php vendor/bin/phpunit
artifacts:
reports:
junit: build/report.junit.xml

在上面的原始碼中,因為已經將 JUnit 格式的報表宣告放在 build/report.junit.xml,因此 script 中執行 PHPUnit 的部分僅剩下 php vendor/bin/phpunit,而 artifacts:reports:junit 的部分則維持不變。

3. 在 ParaTest 中使用 JUnit XML 格式報表

在 PHP 語言中,為了讓 PHPUnit 可以執行的更快,開始有一些加強的方案,如很多人常用的平行化處理方案,透過多執行序來同時執行 PHP 的單元測試以加快完成速度,其中 ParaTest paratestphp/paratest: Parallel testing for PHPUnit 就是這中間很有名的一個工具。

在 ParaTest 中,要怎麼樣宣告產出 JUnit XML 格式的報表呢?在 ParaTest 的手冊中提到,原本在 PHPUnit 中使用的語法,在 ParaTest 基本上都是可以直接相容的,其中 JUnit XML 格式的報表就是相容的項目之一。因此無論是使用 phpunit.xml 宣告,或者是直接使用 Command Line 搭配參數指令執行的方法都是一樣的。如下,首先是使用 phpunit.xml 宣告的方法:

1
2
3
4
5
6
7
8
test:paratest-with-phpunit-file:
extends: .test_template
script:
- mkdir -p build
- vendor/bin/paratest --colors --processes 2 --runner=WrapperRunner
artifacts:
reports:
junit: build/report.junit.xml

上面的原始碼中,比較需要注意的地方是 mkdir -p build 產出資料夾的部分,在目前範例中使用的 ParaTest 6.3 版本中,如果宣告產出報表所在的「資料夾不存在」,那麼在執行 ParaTest 的過程中換產生一段警告,顯示無法寫入檔案。(如下)

1
Warning: file_put_contents(/builds/mouson-gitlab-playground/feature-demo/gitlab-phpunit-gen-junit-report-demo/build/report.junit.xml): Failed to open stream: No such file or directory in /builds/mouson-gitlab-playground/feature-demo/gitlab-phpunit-gen-junit-report-demo/vendor/brianium/paratest/src/Logging/JUnit/Writer.php on line 99

進而造成 GitLab 工作完成後,要打包產出物時,找不到檔案而產出另外一個警告。(如下)

1
2
3
Uploading artifacts...
WARNING: build/report.junit.xml: no matching files
ERROR: No files to upload

因此在範例中,需要特別執行 mkdir -p build 來建立 build 資料夾。

接下來就是使用 Command Line 產出報表的範例:

1
2
3
4
5
6
7
8
test:paratest-with-command-line:
extends: .test_template
script:
- mkdir -p build
- vendor/bin/paratest --colors --processes 2 --runner=WrapperRunner --log-junit build/junit.xml
artifacts:
reports:
junit: build/junit.xml

同上一個範例中,也同樣有 mkdir -p build 這段產出 build 資料夾的部分。其它的如 PHPUnit 在 Command Line 一樣,要產出 JUnit XML 格式的報表必須要透過 --log-junit <file> 參數。

四、結論

在 GitLab CI 中使 PHP 的測試工作 PHPUnit 執行後產出 JUnit XML 格式的報表,主要倚靠 PHPUnit 自身的功能搭配 GitLab CI artifacts:reports:junit 機制來完成,其實不難,但因為可以直接在 Pipeline 中直接查看到執行結果,在單元測試發生錯誤時,就可以馬上透過 Pipeline 中提供的報表直接查看到出錯的位置,減少了好幾個步驟,是個值得增加的設定。

五、參考連結

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器