テストカバレッジの可視化
GitLab CI/CDの助けを借りて、お気に入りのテストツールやカバレッジ分析ツールのテストカバレッジ情報を収集し、マージリクエスト(MR)のファイル差分ビュー内でこの情報を可視化することができます。これにより、MRがマージされる前に、どの行がテストでカバーされ、どの行がまだカバレッジが必要かを確認することができます。
テストカバレッジの可視化の仕組み
カバレッジ情報の収集はGitLabのCI/CDアーティファクトレポート機能を使って行います。収集する1つ以上のカバレッジレポートを、ワイルドカードパスを含めて指定することができます。そしてGitLabは全てのファイルのカバレッジ情報を取得し、結合します。カバレッジファイルはバックグラウンドジョブで解析されるため、パイプラインが完了してからページ上で可視化されるまでに遅延が発生することがあります。
カバレッジ分析が機能するためには、適切なフォーマットのCobertura XMLレポートをartifacts:reports:coverage_report
に提供する必要があります。このフォーマットはもともと Java 用に開発されたものですが、他の言語用のカバレッジ分析フレームワークの多くには、そのサポートを追加するプラグインがあります:
- simplecov-cobertura(Ruby)
- gocover-cobertura(Go)
他のカバレッジ分析フレームワークもこのフォーマットをサポートしています:
- Istanbul(JavaScript)
- Coverage.py(Python)
- PHPUnit (PHP)
設定後、マージリクエストがカバレッジレポートを収集するパイプラインをトリガーした場合、カバレッジ情報が diff ビューに表示されます。これには、パイプラインのどのステージのどのジョブのレポーターも含まれます。カバレッジは行ごとに表示されます:
-
covered
(緑): テストによって少なくとも一度はチェックされた行 -
no test coverage
(オレンジ): 読み込まれたが実行されなかった行 - カバレッジ情報なし: インストゥルメントされていないか、ロードされていない行
カバレッジバーにカーソルを合わせると、その行がテストでチェックされた回数など、さらに詳しい情報が表示されます。
テストカバレッジレポートをアップロードしても有効になりません:
これらは別途設定する必要があります。
限界
Cobertura 形式の XML ファイルには、100<source>
ノードという制限が適用されます。Cobertura レポートが 100 ノードを超える場合、マージリクエスト差分ビューで不一致または一致しないことがあります。
1つの Cobertura XML ファイルは 10 MiB 以下です。大きなプロジェクトでは、Cobertura XML を小さなファイルに分割してください。詳細はこのイシューを参照してください。多数のファイルを送信する場合、マージリクエストでカバレッジが表示されるまでに数分かかることがあります。
可視化はパイプラインが完了してから表示されます。パイプラインに手動ジョブがブロックされている場合、パイプラインは続行する前に手動ジョブを待機し、完了したとは見なされません。ブロック手動ジョブが実行されなかった場合、可視化は表示されません。
データの有効期限
GitLab 13.12で導入され、有効期限に関係なく最新のデータが保持されます。
デフォルトでは、マージリクエストでビジュアライゼーションを描画するために使用されたデータの有効期限は、作成から1週間後です。
子パイプラインからのカバレッジレポート
- GitLab 15.1 で
ci_child_pipeline_coverage_reports
というフラグで導入されました。デフォルトでは無効です。- GitLab.comで有効になり、自己管理され、機能フラグ
ci_child_pipeline_coverage_reports
はGitLab 15.2で削除されました。
子パイプラインのジョブがカバレッジレポートを作成した場合、そのレポートは親パイプラインのカバレッジレポートに含まれます。
child_test_pipeline:
trigger:
include:
- local: path/to/child_pipeline_with_coverage.yml
クラスパスの自動修正
カバレッジレポートは、class
要素のfilename
にプロジェクトルートからの相対パスが含まれている場合にのみ、変更されたファイルに適切にマッチします。しかし、いくつかのカバレッジ分析フレームワークでは、生成されたCobertura XMLは、代わりにクラスパッケージディレクトリへの相対パスfilename
。
プロジェクト・ルートからの相対パスclass
をインテリジェントに推測するために、Cobertura XML パーサーは以下の方法でフル・パスの構築を試みます:
-
sources
要素からsource
パスの一部を抽出し、クラスfilename
パスと組み合わせます。 - 候補パスがプロジェクトに存在するかどうかをチェックします。
- 一致した最初の候補をクラスのフル・パスとして使用します。
パス修正例
例として、以下のような C# プロジェクトがあります:
-
test-org/test-cs-project
のフルパス。 -
プロジェクトルートからの相対パス:
Auth/User.cs Lib/Utils/User.cs
-
sources
Cobertura XMLから、<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...
:<sources> <source>/builds/test-org/test-cs-project/Auth</source> <source>/builds/test-org/test-cs-project/Lib/Utils</source> </sources>
パーサー:
-
sources
からAuth
とLib/Utils
を抽出し、これらを使ってプロジェクトルートからの相対パスclass
を決定します。 - これらの抽出された
sources
とクラス・ファイル名を結合します。たとえば、filename
の値がUser.cs
であるclass
要素がある場合、パーサーは最初に一致するパスの候補を取ります。これはAuth/User.cs
です。 - 各
class
要素について、抽出された各source
パスの一致を 100 回まで試行します。ファイル・ツリーで一致するパスが見つからずにこの制限に達した場合、そのクラスは最終的なカバレッジ・レポートに含まれません。
クラス・パスの自動修正は、以下の Java プロジェクトでも機能します:
-
test-org/test-java-project
のフルパス。 -
プロジェクトルートからの相対パス:
src/main/java/com/gitlab/security_products/tests/App.java
-
sources
Cobertura XMLから:<sources> <source>/builds/test-org/test-java-project/src/main/java/</source> </sources>
-
class
要素のfilename
値はcom/gitlab/security_products/tests/App.java
です:<class name="com.gitlab.security_products.tests.App" filename="com/gitlab/security_products/tests/App.java" line-rate="0.0" branch-rate="0.0" complexity="6.0">
<CI_BUILDS_DIR>/<PROJECT_FULL_PATH>/...
という形式のsource
パスに対してのみ機能します。パスがこのパターンに従わない場合、source
は無視されます。パーサーは、class
要素のfilename
には、プロジェクト・ルートからの相対パスがフル・パスで含まれているとみなします。テストカバレッジの設定例
このセクションでは、さまざまなプログラミング言語のテストカバレッジ設定例を示します。また、coverage-report
デモプロジェクトで動作例を見ることができます。
JavaScript の例
次の.gitlab-ci.yml
の例では、MochaJavaScript テストとnyccoverage-tooling を使ってカバレッジのアーティファクトを生成しています:
test:
script:
- npm install
- npx nyc --reporter cobertura mocha
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml
Java と Kotlin の例
Mavenの例
以下のJavaまたはKotlinの.gitlab-ci.yml
の例では、プロジェクトをビルドするためにMavenを使用し、カバレッジアーティファクトを生成するためにJaCoCoカバレッジツーリングを使用しています。独自のイメージをビルドしたい場合は、Dockerイメージの設定とスクリプトを確認できます。
GitLabはCoberturaフォーマットのアーティファクトを期待しているので、アップロードする前にいくつかのスクリプトを実行する必要があります。test-jdk11
ジョブはコードをテストしてXMLアーティファクトを生成します。coverage-jdk-11
ジョブはアーティファクトを Cobertura レポートに変換します:
test-jdk11:
stage: test
image: maven:3.6.3-jdk-11
script:
- mvn $MAVEN_CLI_OPTS clean org.jacoco:jacoco-maven-plugin:prepare-agent test jacoco:report
artifacts:
paths:
- target/site/jacoco/jacoco.xml
coverage-jdk11:
# Must be in a stage later than test-jdk11's stage.
# The `visualize` stage does not exist by default.
# Please define it first, or choose an existing stage like `deploy`.
stage: visualize
image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
script:
# convert report from jacoco to cobertura, using relative project path
- python /opt/cover2cover.py target/site/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > target/site/cobertura.xml
needs: ["test-jdk11"]
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: target/site/cobertura.xml
Gradleの例
以下のJavaまたはKotlinの.gitlab-ci.yml
の例では、プロジェクトのビルドにGradleを使用し、カバレッジツールの生成にJaCoCoを使用しています。独自のイメージをビルドしたい場合は、Dockerイメージの設定とスクリプトを確認できます。
GitLabはCoberturaフォーマットのアーティファクトを期待しているので、アップロードする前にいくつかのスクリプトを実行する必要があります。test-jdk11
ジョブはコードをテストしてXMLアーティファクトを生成します。coverage-jdk-11
ジョブはアーティファクトを Cobertura レポートに変換します:
test-jdk11:
stage: test
image: gradle:6.6.1-jdk11
script:
- 'gradle test jacocoTestReport' # jacoco must be configured to create an xml report
artifacts:
paths:
- build/jacoco/jacoco.xml
coverage-jdk11:
# Must be in a stage later than test-jdk11's stage.
# The `visualize` stage does not exist by default.
# Please define it first, or chose an existing stage like `deploy`.
stage: visualize
image: registry.gitlab.com/haynes/jacoco2cobertura:1.0.7
script:
# convert report from jacoco to cobertura, using relative project path
- python /opt/cover2cover.py build/jacoco/jacoco.xml $CI_PROJECT_DIR/src/main/java/ > build/cobertura.xml
needs: ["test-jdk11"]
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: build/cobertura.xml
Python example
次の.gitlab-ci.yml
の例では、pytest-covを使ってテストカバレッジデータを収集しています:
run tests:
stage: test
image: python:3
script:
- pip install pytest pytest-cov
- pytest --cov --cov-report term --cov-report xml:coverage.xml
coverage: '/(?i)total.*? (100(?:\.0+)?\%|[1-9]?\d(?:\.\d+)?\%)$/'
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
PHP の例
次の PHP の例.gitlab-ci.yml
では、PHPUnitを使用してテストカバレッジのデータを収集し、 レポートを作成しています。
最小限のphpunit.xml
ファイル (このサンプルのリポジトリを参照ください) があれば、 テストを実行してcoverage.xml
を作成することができます:
run tests:
stage: test
image: php:latest
variables:
XDEBUG_MODE: coverage
before_script:
- apt-get update && apt-get -yq install git unzip zip libzip-dev zlib1g-dev
- docker-php-ext-install zip
- pecl install xdebug && docker-php-ext-enable xdebug
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php --install-dir=/usr/local/bin --filename=composer
- composer install
- composer require --dev phpunit/phpunit phpunit/php-code-coverage
script:
- php ./vendor/bin/phpunit --coverage-text --coverage-cobertura=coverage.cobertura.xml
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.cobertura.xml
Codeception では、PHPUnit を通して、run
を使った Cobertura レポートの生成もサポートしています。生成されるファイルのパスは、--coverage-cobertura
オプションとユニットテストスイートのpaths
設定に依存します。適切なパスに Cobertura を見つけるように.gitlab-ci.yml
を設定してください。
C/C++の例
コンパイラとしてgcc
またはg++
を使用した C/C++ の次の.gitlab-ci.yml
の例では、gcovr
を使用して Cobertura XML 形式のカバレッジ出力ファイルを生成しています。
この例では
-
Makefile
は、build
ディレクトリのcmake
によって、前のステージの別のジョブ内部で作成されます。(Makefile
を生成するためにautomake
を使用する場合は、make test
の代わりにmake check
を呼び出す必要があります)。 -
cmake
(またはautomake
)がコンパイラ・オプション--coverage
を設定していること。
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
Goの例
次の.gitlab-ci.yml
、Goの例です:
-
go test
を使ってテストを実行します。 -
gocover-cobertura
を使用して、Go のカバレッジ・プロファイルを Cobertura XML フォーマットに変換します。
この例では、Go モジュールを使用することを前提としています。-covermode count
オプションはフラグと併用できません-race
。 -race
フラグを-race
使用しながらコードカバレッジを生成したい -race
場合は、-covermode count
よりも遅い-covermode atomic
に切り替える必要があります。 詳細はこちらのブログ記事を参照してください。
run tests:
stage: test
image: golang:1.17
script:
- go install
- go test ./... -coverprofile=coverage.txt -covermode count
- go get github.com/boumenot/gocover-cobertura
- go run github.com/boumenot/gocover-cobertura < coverage.txt > coverage.xml
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage.xml
Rubyの例
以下のRubyの.gitlab-ci.yml
。
-
rspec
を使ってテストを実行します。 -
simplecov
およびsimplecov-cobertura
を使用してカバレッジプロファイルを記録し、Cobertura XML 形式でレポートを作成します。
この例では
-
bundler
が依存関係管理に使用されていること。rspec
,simplecov
およびsimplecov-cobertura
gems がGemfile
に追加されています。 -
CoberturaFormatter
がspec_helper.rb
ファイル内のSimpleCov.formatters
設定に追加されています。
run tests:
stage: test
image: ruby:3.1
script:
- bundle install
- bundle exec rspec
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: coverage/coverage.xml
トラブルシューティング
テスト・カバレッジの可視化が表示されない
差分ビューにテストカバレッジの可視化が表示されない場合は、カバレッジレポート自体を確認して確認することができます:
- 差分ビューで表示しているファイルがカバレッジレポートに記載されているかどうか。
- レポート内の
source
とfilename
ノードは、リポジトリ内のファイルと一致するよう、予想される構造に従っています。 - パイプラインが完了しました。手動ジョブでパイプラインがブロックされている場合、パイプラインは完了したとは見なされません。
- カバレッジレポートファイルが制限を超えていません。
レポートアーティファクトはデフォルトではダウンロードできません。ジョブ詳細ページからレポートをダウンロードできるようにするには、カバレッジ・レポートをアーティファクトpaths
に追加してください:
artifacts:
paths:
- coverage/cobertura-coverage.xml
reports:
coverage_report:
coverage_format: cobertura
path: coverage/cobertura-coverage.xml