Bazel には、bazel coverage
でテストできるリポジトリに関するコード カバレッジ レポートを生成する coverage
サブコマンドがあります。さまざまな言語エコシステムには固有の性質があるため、特定のプロジェクトでこれを行うことは必ずしも容易ではありません。
このページでは、カバレッジ レポートを作成して表示する一般的なプロセスについて説明します。また、よく知られた言語について、言語固有の注意事項についても説明します。最初に一般的なセクションを読んでから、特定の言語の要件をお読みください。リモート実行セクションにも注意してください。ここには追加の考慮事項があります。
さまざまなカスタマイズが可能ですが、このドキュメントでは、現在最もサポートされているルートである lcov
レポートの作成と使用に焦点を当てています。
カバレッジ レポートの作成
準備
カバレッジ レポートの基本的なワークフローは次のとおりです。
- テスト ターゲットを含む基本的なリポジトリ
- 言語固有のコード カバレッジ ツールがインストールされているツールチェーン
- 正しい「インストルメンテーション」構成
前者の 2 つは言語固有のものであり、大部分が単純ですが、後者は複雑なプロジェクトではより難しくなる場合があります。
この場合の「インストルメンテーション」とは、特定のターゲットに使用されるカバレッジ ツールを指します。Bazel では、--instrumentation_filter
フラグを使用して、ファイルの特定のサブセットに対してこの機能を有効にできます。このフラグは、インストルメンテーションを有効にしてテストされるターゲットのフィルタを指定します。テストのインストルメンテーションを有効にするには、--instrument_test_targets
フラグが必要です。
デフォルトでは、bazel はターゲット パッケージを一致させ、関連するフィルタを INFO
メッセージとして出力します。
ランニング カバレッジ
カバレッジ レポートを作成するには、bazel coverage
--combined_report=lcov
[target]
を使用します。これにより、ターゲットに対してテストが実行され、ファイルごとに lcov 形式のカバレッジ レポートが生成されます。
完了すると、bazel は生成されたすべてのカバレッジ ファイルを収集して 1 つに統合するアクションを実行します。このアクションは最終的に $(bazel info
output_path)/_coverage/_coverage_report.dat
に作成されます。
カバレッジ レポートはテストが失敗した場合でも生成されますが、これは失敗したテストまでは対象外であり、合格したテストのみが報告されます。
カバレッジの確認
カバレッジ レポートは、人間が判読できない lcov
形式でのみ出力されます。ここから、genhtml
ユーティリティ(lcov プロジェクトの一部)を使用して、ウェブブラウザで表示できるレポートを生成できます。
genhtml --output genhtml "$(bazel info output_path)/_coverage/_coverage_report.dat"
genhtml
はソースコードも読み取り、これらのファイルで欠落しているカバレッジにアノテーションを付けます。これを行うには、genhtml
が bazel プロジェクトのルートで実行される必要があります。
結果を表示するには、genhtml
ディレクトリにある index.html
ファイルを任意のウェブブラウザで開きます。
genhtml
ツールまたは lcov
カバレッジ形式に関するヘルプと詳細については、lcov プロジェクトをご覧ください。
リモート実行
リモートテスト実行で実行した場合の注意点は次のとおりです。
- 現時点では、レポートの組み合わせの操作をリモートで実行することはできません。これは、Bazel がカバレッジ出力ファイルをグラフの一部として考慮しないため(この問題を参照)、組み合わせアクションへの入力として正しく処理できないためです。この問題を回避するには、
--strategy=CoverageReport=local
を使用します。- 注: Bazel が戦略を解決する方法のため、
local,remote
を試すように Bazel がセットアップされている場合は、--strategy=CoverageReport=local,remote
などを指定しなければならないことがあります。
- 注: Bazel が戦略を解決する方法のため、
--remote_download_minimal
などのフラグも、前者の理由で使用できません。- 現在、テストが以前にキャッシュに保存されている場合、Bazel はカバレッジ情報を作成できません。この問題を回避するには、
--nocache_test_results
をカバレッジ実行に対して特に設定します。ただし、テスト時間には大きな負担がかかります。 --experimental_split_coverage_postprocessing
と--experimental_fetch_all_coverage_outputs
- 通常、カバレッジはテスト アクションの一部として実行されるため、デフォルトでは、すべてのカバレッジがリモート実行の出力として返されるわけではありません。これらのフラグはデフォルトをオーバーライドし、カバレッジ データを取得します。詳細については、この問題をご覧ください。
言語固有の構成
Java
Java は、デフォルト設定ですぐに使用できます。bazel ツールチェーンには、JUnit を含め、リモート実行に必要なすべてのものが含まれています。
Python
前提条件
Python でカバレッジを実行するには、いくつかの前提条件があります。
- b01c859 を含む bazel バイナリ(Bazel 3.0 以降である必要があります)。
- coverage.py の修正版。
変更した coverage.py の使用
これを行うには、rules_python を使用します。これにより、requirements.txt
ファイルを使用できます。ファイルにリストされている要件は、pip_install リポジトリ ルールを使用して bazel ターゲットとして作成されます。
requirements.txt
のエントリは次のとおりです。
git+https://github.com/ulfjack/coveragepy.git@lcov-support
rules_python
、pip_install
、requirements.txt
ファイルは、次のように WORKSPACE ファイルで使用する必要があります。
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "rules_python",
url = "https://github.com/bazelbuild/rules_python/releases/download/0.5.0/rules_python-0.5.0.tar.gz",
sha256 = "cd6730ed53a002c56ce4e2f396ba3b3be262fd7cb68339f0377a45e8227fe332",
)
load("@rules_python//python:pip.bzl", "pip_install")
pip_install(
name = "python_deps",
requirements = "//:requirements.txt",
)
BUILD
ファイルで次のように設定すると、coverage.py 要件をテスト ターゲットで使用できます。
load("@python_deps//:requirements.bzl", "entry_point")
alias(
name = "python_coverage_tools",
actual = entry_point("coverage"),
)
py_test(
name = "test",
srcs = ["test.py"],
env = {
"PYTHON_COVERAGE": "$(location :python_coverage_tools)",
},
deps = [
":main",
":python_coverage_tools",
],
)
密閉型の Python ツールチェーンを使用している場合は、すべての py_test
ターゲットにカバレッジの依存関係を追加する代わりに、ツールチェーンの構成にカバレッジ ツールを追加できます。
pip_install ルールは Python ツールチェーンに依存するため、これを使用して coverage
モジュールを取得することはできません。代わりに、WORKSPACE
を追加します。たとえば、
http_archive(
name = "coverage_linux_x86_64"",
build_file_content = """
py_library(
name = "coverage",
srcs = ["coverage/__main__.py"],
data = glob(["coverage/*", "coverage/**/*.py"]),
visibility = ["//visibility:public"],
)
""",
sha256 = "84631e81dd053e8a0d4967cedab6db94345f1c36107c71698f746cb2636c63e3",
type = "zip",
urls = [
"https://files.pythonhosted.org/packages/74/0d/0f3c522312fd27c32e1abe2fb5c323b583a5c108daf2c26d6e8dfdd5a105/coverage-6.4.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
],
)
次に、Python ツールチェーンを以下のように構成します。
py_runtime(
name = "py3_runtime_linux_x86_64",
coverage_tool = "@coverage_linux_x86_64//:coverage",
files = ["@python3_9_x86_64-unknown-linux-gnu//:files"],
interpreter = "@python3_9_x86_64-unknown-linux-gnu//:bin/python3",
python_version = "PY3",
)
py_runtime_pair(
name = "python_runtimes_linux_x86_64",
py2_runtime = None,
py3_runtime = ":py3_runtime_linux_x86_64",
)
toolchain(
name = "python_toolchain_linux_x86_64",
exec_compatible_with = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
],
toolchain = ":python_runtimes_linux_x86_64",
toolchain_type = "@bazel_tools//tools/python:toolchain_type",
)