| --- | |
| title: 'Code coverage with Bazel' | |
| --- | |
| Bazel features a `coverage` sub-command to produce code coverage | |
| reports on repositories that can be tested with `bazel coverage`. Due | |
| to the idiosyncrasies of the various language ecosystems, it is not | |
| always trivial to make this work for a given project. | |
| This page documents the general process for creating and viewing | |
| coverage reports, and also features some language-specific notes for | |
| languages whose configuration is well-known. It is best read by first | |
| reading [the general section](#creating-a-coverage-report), and then | |
| reading about the requirements for a specific language. | |
| While a lot of customization is possible, this document focuses on | |
| producing and consuming [`lcov`][lcov] reports, which is currently the | |
| most well-supported route. | |
| ## Creating a coverage report {#creating-a-coverage-report} | |
| ### Preparation | |
| The basic workflow for creating coverage reports requires the | |
| following: | |
| - A basic repository with test targets | |
| - A toolchain with the language-specific code coverage tools installed | |
| - A correct "instrumentation" configuration | |
| The former two are language-specific and mostly straightforward, | |
| however the latter can be more difficult for complex projects. | |
| "Instrumentation" in this case refers to the coverage tools that are | |
| used for a specific target. Bazel allows turning this on for a | |
| specific subset of files using the | |
| [`--instrumentation_filter`](/reference/command-line-reference#flag--instrumentation_filter) | |
| flag, which specifies a filter for targets that are tested with the | |
| instrumentation enabled. To enable instrumentation for tests, the | |
| [`--instrument_test_targets`](/reference/command-line-reference#flag--instrument_test_targets) | |
| flag is required. | |
| By default, bazel tries to match the target package(s), and prints the | |
| relevant filter as an `INFO` message. | |
| ### Running coverage | |
| To produce a coverage report, use [`bazel coverage | |
| --combined_report=lcov | |
| [target]`](/reference/command-line-reference#coverage). This runs the | |
| tests for the target, generating coverage reports in the lcov format | |
| for each file. | |
| Once finished, bazel runs an action that collects all the produced | |
| coverage files, and merges them into one, which is then finally | |
| created under `$(bazel info | |
| output_path)/_coverage/_coverage_report.dat`. | |
| Coverage reports are also produced if tests fail, though note that | |
| this does not extend to the failed tests - only passing tests are | |
| reported. | |
| ### Viewing coverage | |
| The coverage report is only output in the non-human-readable `lcov` | |
| format. From this, we can use the `genhtml` utility (part of [the lcov | |
| project][lcov]) to produce a report that can be viewed in a web | |
| browser: | |
| ```console | |
| genhtml --branch-coverage --output genhtml "$(bazel info output_path)/_coverage/_coverage_report.dat" | |
| ``` | |
| Note that `genhtml` reads the source code as well, to annotate missing | |
| coverage in these files. For this to work, it is expected that | |
| `genhtml` is executed in the root of the bazel project. | |
| To view the result, simply open the `index.html` file produced in the | |
| `genhtml` directory in any web browser. | |
| For further help and information around the `genhtml` tool, or the | |
| `lcov` coverage format, see [the lcov project][lcov]. | |
| ## Language-specific configuration | |
| ### C++ | |
| #### Linux | |
| C++ coverage should work out-of-the-box with the default configuration. | |
| #### MacOS | |
| The default value of `GCOV_PREFIX_STRIP` is almost certainly incorrect and needs | |
| adjusting manually because the correct value depends on your setup. | |
| When the value is incorrect, no coverage data will be found. | |
| Example to set `GCOV_PREFIX_STRIP=10` | |
| ``` | |
| bazel coverage //foo:foo_test --test_env=GCOV_PREFIX_STRIP=10` | |
| ``` | |
| ### Java | |
| Java should work out-of-the-box with the default configuration. The | |
| [bazel toolchains][bazel_toolchains] contain everything necessary for | |
| remote execution, as well, including JUnit. | |
| ### Python | |
| See the [`rules_python` coverage docs](https://rules-python.readthedocs.io/en/latest/coverage.html) | |
| for additional steps needed to enable coverage support in Python. | |
| [lcov]: https://github.com/linux-test-project/lcov | |
| [bazel_toolchains]: https://github.com/bazelbuild/bazel-toolchains |