Codeabdeckung mit Bazel

Bazel enthält den Unterbefehl coverage, um Berichte zur Codeabdeckung für Repositories zu generieren, die mit bazel coverage getestet werden können. Aufgrund der Besonderheiten der verschiedenen Sprachsystemen ist es nicht immer einfach, diese Arbeit für ein bestimmtes Projekt umzusetzen.

Auf dieser Seite wird der allgemeine Prozess zum Erstellen und Aufrufen von Abdeckungsberichten dokumentiert. Außerdem finden Sie hier einige sprachspezifische Hinweise für Sprachen, deren Konfiguration bekannt ist. Am besten lesen Sie sich zuerst den allgemeinen Abschnitt durch und lesen dann die Anforderungen für eine bestimmte Sprache. Beachten Sie auch den Abschnitt zur Remote-Ausführung. Dafür sind einige weitere Aspekte zu beachten.

Obwohl viele Anpassungen möglich sind, konzentriert sich dieses Dokument auf die Erstellung und Nutzung von lcov-Berichten, die derzeit die am besten unterstützte Route ist.

Bericht zur Indexabdeckung erstellen

Vorbereitung

Der grundlegende Workflow zum Erstellen von Abdeckungsberichten erfordert Folgendes:

  • Ein grundlegendes Repository mit Testzielen
  • Eine Toolchain mit den installierten sprachspezifischen Codeabdeckungstools
  • Eine korrekte Instrumentierungskonfiguration

Die ersten beiden sind sprachspezifisch und überwiegend unkompliziert, letztere können jedoch für komplexe Projekte schwieriger sein.

"Instrumentierung" bezieht sich in diesem Fall auf die Abdeckungstools, die für ein bestimmtes Ziel verwendet werden. Bazel ermöglicht die Aktivierung für eine bestimmte Teilmenge von Dateien mit dem Flag --instrumentation_filter, das einen Filter für Ziele angibt, die mit der Instrumentierung getestet werden. aktiviert. Zum Aktivieren der Instrumentierung für Tests ist das Flag --instrument_test_targets erforderlich.

Standardmäßig versucht Baizel, die Zielpakete abzugleichen, und gibt den relevanten Filter als INFO-Nachricht aus.

Laufende Abdeckung

Wenn Sie einen Abdeckungsbericht erstellen möchten, verwenden Sie bazel coverage --combined_report=lcov [target]. Damit werden die Tests für das Ziel ausgeführt und Abdeckungsberichte im LCOV-Format für jede Datei generiert.

Danach führt bazel eine Aktion aus, die alle erzeugten Coverdateien sammelt und zu einer einzigen Datei zusammenfasst, die dann schließlich unter $(bazel info output_path)/_coverage/_coverage_report.dat erstellt wird.

Abdeckungsberichte werden auch erstellt, wenn Tests fehlschlagen. Dies gilt jedoch nicht für die fehlgeschlagenen Tests – es werden nur bestandene Tests gemeldet.

Abdeckung wird angezeigt

Der Bericht zur Abdeckung wird nur im nicht lesbaren lcov-Format ausgegeben. Aus diesem Grund können wir mit dem Dienstprogramm genhtml (Teil des lcov-Projekts) einen Bericht erstellen, der in einem Webbrowser aufgerufen werden kann:

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

Beachten Sie, dass genhtml auch den Quellcode liest, um fehlende Abdeckung in diesen Dateien zu annotieren. Damit das funktioniert, wird erwartet, dass genhtml im Stammverzeichnis des Projekts ausgeführt wird.

Um das Ergebnis anzusehen, öffnen Sie einfach die Datei index.html, die im Verzeichnis genhtml erstellt wurde, in einem beliebigen Webbrowser.

Weitere Hilfe und Informationen zum genhtml-Tool oder zum Abdeckungsformat lcov finden Sie unter lcov-Projekt.

Remote-Ausführung

Die Ausführung mit Remote-Testausführung hat derzeit einige Einschränkungen:

  • Die Kombinationsaktion für Berichte kann noch nicht remote ausgeführt werden. Das liegt daran, dass Bazel die Abdeckungs-Ausgabedateien nicht als Teil ihrer Grafik behandelt (siehe dieses Problem) und sie daher nicht korrekt als Eingaben für die Kombination behandeln kann. . Zur Problemumgehung verwenden Sie --strategy=CoverageReport=local.
    • Hinweis: Es kann erforderlich sein, stattdessen etwas wie --strategy=CoverageReport=local,remote anzugeben, wenn Bazel eingerichtet ist, um local,remote auszuprobieren. Dies hängt mit der Methode zusammen, mit der Bazel Strategien auflöst.
  • --remote_download_minimal und ähnliche Flags können ebenfalls keine Konsequenz eines ersteren sein.
  • Bazel kann derzeit keine Abdeckungsinformationen erstellen, wenn Tests zuvor im Cache gespeichert wurden. Zur Umgehung dieses Problems kann --nocache_test_results speziell für Abdeckungsausführungen festgelegt werden. Dies verursacht jedoch in Bezug auf die Testzeit natürlich hohe Kosten.
  • --experimental_split_coverage_postprocessing und --experimental_fetch_all_coverage_outputs
    • In der Regel wird die Abdeckung im Rahmen der Testaktion ausgeführt. Daher erhalten wir standardmäßig nicht alle Ergebnisse als Ausgabe der Remote-Ausführung zurück. Diese Flags überschreiben die Standardeinstellung und rufen die Abdeckungsdaten ab. Weitere Informationen finden Sie in diesem Thema.

Sprachspezifische Konfiguration

Java

Java sollte mit der Standardkonfiguration sofort einsatzbereit sein. Die Bazel-Toolchains enthalten auch alles, was für die Remote-Ausführung erforderlich ist, einschließlich JUnit.

Python

Vorbereitung

Für die Ausführung von Abdeckung mit Python gelten einige Voraussetzungen:

Geänderte Abdeckung.py nutzen

Das geht so:rules_python haben Sie hier die Möglichkeit, requirements.txt enthalten, werden die in der Datei aufgeführten Anforderungen dann mithilfe der pip_install Repository-Regel.

requirements.txt sollte den folgenden Eintrag enthalten:

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

Die Dateien rules_python, pip_install und requirements.txt sollten dann in der WORKSPACE-Datei folgendermaßen verwendet werden:

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

Die Anforderung "cover.py" kann dann von Testzielen genutzt werden, indem Sie in BUILD-Dateien Folgendes festlegen:

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