Покрытие кода с помощью Bazel

В Bazel есть подкоманда coverage для создания отчетов о покрытии кода в репозиториях, которые можно протестировать с bazel coverage . Из-за особенностей различных языковых экосистем не всегда просто сделать так, чтобы это работало для данного проекта.

На этой странице описан общий процесс создания и просмотра отчетов о покрытии, а также приведены некоторые примечания, относящиеся к языку, конфигурация которых хорошо известна. Лучше всего читать сначала общий раздел , а потом читать о требованиях к конкретному языку. Обратите также внимание на раздел удаленного выполнения , который требует некоторых дополнительных соображений.

Несмотря на то, что возможна большая настройка, этот документ посвящен созданию и использованию отчетов lcov , что в настоящее время является наиболее хорошо поддерживаемым маршрутом.

Создание отчета о покрытии

Подготовка

Базовый рабочий процесс для создания отчетов о покрытии требует следующего:

  • Базовый репозиторий с тестовыми целями
  • Цепочка инструментов с установленными инструментами покрытия кода для конкретного языка.
  • Правильная "приборная" конфигурация

Первые два зависят от языка и в основном просты, однако последний может быть более сложным для сложных проектов.

«Инструментарий» в данном случае относится к инструментам покрытия, которые используются для конкретной цели. Bazel позволяет включить это для определенного подмножества файлов с помощью флага --instrumentation_filter , который указывает фильтр для целей, тестируемых с включенным инструментарием. Чтобы включить инструменты для тестов, требуется флаг --instrument_test_targets .

По умолчанию INFO пытается сопоставить целевые пакеты и выводит соответствующий фильтр в виде информационного сообщения.

Беговое покрытие

Чтобы создать отчет о покрытии, используйте bazel coverage --combined_report=lcov [target] . Это запускает тесты для цели, создавая отчеты о покрытии в формате lcov для каждого файла.

После завершения bazel запускает действие, которое собирает все созданные файлы покрытия и объединяет их в один, который затем, наконец, создается в $(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.

Чтобы просмотреть результат, просто откройте файл index.html , созданный в каталоге genhtml в любом веб-браузере.

Для получения дополнительной помощи и информации об инструменте genhtml или формате покрытия lcov см. проект lcov .

Удаленное исполнение

Запуск с удаленным выполнением тестов в настоящее время имеет несколько предостережений:

  • Действие объединения отчетов пока не может выполняться удаленно. Это связано с тем, что Bazel не рассматривает выходные файлы покрытия как часть своего графа (см. этот выпуск ) и, следовательно, не может правильно рассматривать их как входные данные для действия объединения. Чтобы обойти это, используйте --strategy=CoverageReport=local .
    • Примечание. Может потребоваться указать что-то вроде --strategy=CoverageReport=local,remote вместо этого, если Bazel настроен на попытку local,remote из-за того, как Bazel разрешает стратегии.
  • --remote_download_minimal и подобные флаги также нельзя использовать как следствие первого.
  • В настоящее время Bazel не сможет создать информацию о покрытии, если тесты ранее были кэшированы. Чтобы обойти это, --nocache_test_results может быть установлен специально для прогонов покрытия, хотя это, конечно, влечет за собой большие затраты с точки зрения времени тестирования.
  • --experimental_split_coverage_postprocessing и --experimental_fetch_all_coverage_outputs
    • Обычно покрытие запускается как часть тестового действия, поэтому по умолчанию мы не получаем все покрытие обратно в виде результатов удаленного выполнения по умолчанию. Эти флаги переопределяют значения по умолчанию и получают данные о покрытии. Подробнее см. в этом выпуске .

Конфигурация для конкретного языка

Джава

Java должна работать «из коробки» с конфигурацией по умолчанию. Инструментальные цепочки bazel также содержат все необходимое для удаленного выполнения, включая JUnit.

Питон

Предпосылки

Запуск покрытия с помощью python требует некоторых предварительных условий:

Использование измененного покрытия.py

Это можно сделать с помощью rules_python , это дает возможность использовать файл requirements.txt , требования, перечисленные в файле, затем создаются как цели bazel с использованием правила репозитория pip_install .

В 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",
)

Требование cover.py затем может быть использовано целевыми объектами тестирования путем установки следующих параметров в файлах BUILD :

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",
    ],
)