Copertura del codice con Bazel

Bazel utilizza un sottocomando coverage per produrre rapporti sulla copertura del codice sui repository che possono essere testati con bazel coverage. A causa delle caratteristiche di interazione con i diversi ecosistemi linguistici, non è sempre banale eseguire questa operazione per un dato progetto.

Questa pagina documenta la procedura generale per la creazione e la visualizzazione dei rapporti sulla copertura. Inoltre, offre alcune note sulla lingua specifiche per le lingue la cui configurazione è già nota. La prima cosa da fare è leggere la sezione generale e poi leggere i requisiti relativi a una lingua specifica. Nota anche la sezione relativa all'esecuzione remota, che richiede alcune considerazioni aggiuntive.

Sebbene sia possibile effettuare molte personalizzazioni, questo documento si concentra sulla produzione e il consumo di rapporti lcov, che attualmente è il percorso più supportato.

Creazione di un rapporto sulla copertura

Preparazione

Il flusso di lavoro di base per la creazione dei rapporti di copertura richiede quanto segue:

  • Un repository di base con destinazioni di test
  • Una toolchain con gli strumenti di copertura del codice specifici per un linguaggio installato
  • Una configurazione di "strumentazione" corretta

I primi due sono specifici per la lingua e per lo più semplici, mentre i secondi possono essere più difficili per progetti complessi.

In questo caso, la "strumentazione" si riferisce agli strumenti di copertura utilizzati per un target specifico. Bazel consente di attivare questa opzione per un sottoinsieme specifico di file utilizzando il flag --instrumentation_filter, che specifica un filtro per le destinazioni testate con la strumentazione. Per abilitare la strumentazione per i test, è obbligatorio il flag --instrument_test_targets.

Per impostazione predefinita, bazel cerca di trovare i pacchetti di destinazione e stampa il filtro pertinente come un messaggio INFO.

Copertura in corso

Per creare un rapporto sulla copertura, utilizza bazel coverage --combined_report=lcov [target]. In questo modo viene eseguito il test della destinazione, generando rapporti di copertura nel formato lcov per ogni file.

Al termine, bazel esegue un'azione che raccoglie tutti i file di copertura prodotti e li unisce in uno, che successivamente viene creato in $(bazel info output_path)/_coverage/_coverage_report.dat.

I rapporti sulla copertura vengono generati anche se i test non hanno esito positivo, ma tieni presente che questo non si estende ai test non superati, ma solo il superamento dei test.

Visualizzazione della copertura

Il rapporto sulla copertura viene restituito solo in formato lcov non leggibile. Di conseguenza, possiamo utilizzare l'utilità genhtml (parte del progetto lcov) per produrre un rapporto visualizzabile in un browser web:

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

Tieni presente che genhtml legge anche il codice sorgente per annotare la copertura mancante in questi file. Per il corretto funzionamento della funzionalità, si prevede che genhtml venga eseguito nella radice del progetto bazel.

Per visualizzare il risultato, apri semplicemente il file index.html prodotto nella directory genhtml in qualsiasi browser web.

Per ulteriore assistenza e informazioni sugli strumenti genhtml o sul formato di copertura lcov, consulta il progetto lcov.

Esecuzione da remoto

Al momento, l'esecuzione con l'esecuzione di test da remoto comporta alcune avvertenze:

  • L'azione associata al rapporto non può ancora essere eseguita da remoto. Ciò è dovuto al fatto che Bazel non considera i file di output della copertura all'interno del grafico (vedi questo problema) e, di conseguenza, non può considerarli correttamente come input per la combinazione. . Per aggirare il problema, utilizza --strategy=CoverageReport=local.
    • Nota: potrebbe essere necessario specificare qualcosa come --strategy=CoverageReport=local,remote, se Bazel è impostato per provare local,remote, a causa del modo in cui Bazel risolve le strategie.
  • --remote_download_minimal e i flag simili non possono essere utilizzati nemmeno come conseguenza del primo.
  • Attualmente Bazel non sarà in grado di creare informazioni sulla copertura se i test sono stati precedentemente memorizzati nella cache. Per ovviare a questo problema, --nocache_test_results può essere impostato specificamente per le esecuzioni di copertura, anche se questo comporta ovviamente costi elevati in termini di tempi di test.
  • --experimental_split_coverage_postprocessing e --experimental_fetch_all_coverage_outputs
    • In genere la copertura viene eseguita come parte dell'azione di test e, di conseguenza, per impostazione predefinita non otteniamo tutta la copertura come output dell'esecuzione remota. Questi flag sostituiscono l'impostazione predefinita e ottengono i dati sulla copertura. Consulta questo problema per ulteriori dettagli.

Configurazione specifica per lingua

Java

Java dovrebbe funzionare immediatamente con la configurazione predefinita. Le succedette di bazel contengono anche tutto ciò che è necessario per l'esecuzione da remoto, incluso JUnit.

Python

Prerequisiti

L'esecuzione della copertura con python ha alcuni prerequisiti:

Utilizzo della copertura modificata.py

Un modo per farlo è tramiteregole_python, in questo modo puoi utilizzare unrequirements.txt, i requisiti elencati nel file vengono quindi creati come target bazel utilizzando il pip_installazione.

requirements.txt deve avere la seguente voce:

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

I file rules_python, pip_install e requirements.txt devono quindi essere utilizzati nel file WORKSPACE come segue:

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

Il requisito coverage.py può essere utilizzato dalle destinazioni dei test impostando quanto segue nei file 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",
    ],
)