Cobertura de código com o Bazel

Informar um problema Mostrar fonte Por noite · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

O Bazel inclui um subcomando coverage para produzir cobertura de código relatórios sobre repositórios que podem ser testados com bazel coverage. Valor devido às idiossincrasias dos vários ecossistemas linguísticos, isso não é sempre trivial para fazer isso funcionar para um determinado projeto.

Esta página documenta o processo geral para criar e visualizar relatórios de cobertura e também traz algumas observações específicas por idioma para linguagens com configuração bem conhecida. É melhor ler primeiro lendo a seção geral e depois lendo sobre os requisitos de uma linguagem específica. Observe também o seção de execução remota, que requer algumas considerações adicionais.

Embora muitas personalizações sejam possíveis, este documento se concentra em produzem e consomem relatórios do lcov, que atualmente a rota mais aceita.

Como criar um relatório de cobertura

Preparação

O fluxo de trabalho básico para criar relatórios de cobertura exige o seguinte:

  • Um repositório básico com destinos de teste
  • Um conjunto de ferramentas com as ferramentas de cobertura de código específicas da linguagem instaladas
  • Uma "instrumentação" correta configuração

As duas primeiras são específicas da linguagem e, na maioria, diretas, No entanto, a última pode ser mais difícil para projetos complexos.

"Instrumentação" nesse caso se refere às ferramentas de cobertura que estão usada para um alvo específico. O Bazel permite ativar esse recurso subconjunto específico de arquivos usando --instrumentation_filter que especifica um filtro para destinos que são testados com o com a instrumentação ativada. Para ativar a instrumentação para testes, o --instrument_test_targets é obrigatória.

Por padrão, o Bazel tenta corresponder aos pacotes de destino e imprime o filtro relevante como uma mensagem INFO.

Cobertura em execução

Para gerar um relatório de cobertura, use bazel coverage --combined_report=lcov [target]. O comando para o alvo, gerando relatórios de cobertura no formato lcov para cada arquivo.

Depois de terminar, Bazel realiza uma ação que coleta todo o e os mescla em um só arquivo, que é criado em $(bazel info output_path)/_coverage/_coverage_report.dat.

Os relatórios de cobertura também serão gerados se os testes falharem. No entanto, observe que Isso não se estende aos testes com falha - apenas os testes aprovados são relatadas.

Visualização da cobertura

O relatório de cobertura só é gerado em lcov não legível. . A partir disso, podemos usar o utilitário genhtml (parte do lcov projeto) para produzir um relatório que pode ser visualizado em um navegador:

genhtml --output genhtml "$(bazel info output_path)/_coverage/_coverage_report.dat"

Observe que o genhtml também lê o código-fonte para anotar informações ausentes. nos arquivos. Para que isso funcione, espera-se que genhtml é executado na raiz do projeto Bazel.

Para ver o resultado, basta abrir o arquivo index.html produzido no genhtml em qualquer navegador da Web.

Para mais ajuda e informações sobre a ferramenta genhtml ou as lcov, consulte o projeto lcov (em inglês).

Execução remota

No momento, a execução com a execução de teste remoto tem algumas ressalvas:

  • Ainda não é possível executar remotamente a ação de combinação de relatórios. Isso é porque ele não considera os arquivos de saída de cobertura como parte gráfico (consulte este problema) e, portanto, não as tratam corretamente como entradas para a ação de combinação. Para uma solução alternativa, use --strategy=CoverageReport=local.
    • Observação: pode ser necessário especificar algo como --strategy=CoverageReport=local,remote, se o Bazel estiver definido para testar local,remote, devido à forma como o Bazel resolve estratégias.
  • Também não é possível usar --remote_download_minimal e sinalizações semelhantes como consequência da primeira.
  • No momento, o Bazel não cria informações de cobertura se os testes já foram armazenados em cache. Para contornar isso, --nocache_test_results pode ser definido especificamente para execuções de cobertura. embora isso tenha um alto custo em termos de tempo de teste.
  • --experimental_split_coverage_postprocessing e --experimental_fetch_all_coverage_outputs
    • Normalmente, a cobertura é executada como parte da ação de teste e, portanto, Por padrão, não recebemos toda a cobertura de volta como saídas do controle a execução por padrão. Essas sinalizações substituem o padrão e obtêm dos dados de cobertura. Consulte este problema para saber mais detalhes.

Configuração específica da linguagem

Java

O Java deve funcionar pronto para uso com a configuração padrão. A bazel Datasets contêm tudo o que é necessário para a execução remota, inclusive do JUnit.

Python

Pré-requisitos

A execução da cobertura com Python tem alguns pré-requisitos:

Como consumir o cover.py modificado

Uma maneira de fazer isso é usando rules_python, que fornece usar um arquivo requirements.txt, os requisitos listados do arquivo são criados como destinos do Bazel usando regra de repositório pip_install.

O requirements.txt precisa ter a seguinte entrada:

git+https://github.com/ulfjack/coveragepy.git@lcov-support

rules_python, pip_install e o arquivo requirements.txt precisam ser usados no arquivo ESPAÇO DE TRABALHO da seguinte forma:

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

Dessa forma, o requisito coverage.py pode ser consumido por destinos de teste ao definindo o seguinte nos arquivos 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",
    ],
)

Se você estiver usando um conjunto de ferramentas hermético do Python, em vez de adicionar a cobertura a cada destino py_test. Em vez disso, adicione a ferramenta de cobertura a configuração do conjunto de ferramentas.

Como a regra pip_install depende da biblioteca Python ele não poderá ser usado para buscar o módulo coverage. Em vez disso, adicione seu WORKSPACE. Por exemplo:

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

Em seguida, configure o conjunto de ferramentas do Python como, por exemplo:

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