Mức độ sử dụng mã với Bazel

Bazel có một lệnh con coverage để tạo báo cáo mức độ sử dụng mã trên các kho lưu trữ có thể được kiểm thử bằng bazel coverage. Do đặc điểm riêng của các hệ sinh thái ngôn ngữ, nên không phải lúc nào cũng dễ dàng để thực hiện việc này cho một dự án nhất định.

Trang này ghi lại quy trình chung để tạo và xem báo cáo mức độ sử dụng, đồng thời có một số lưu ý dành riêng cho ngôn ngữ đối với các ngôn ngữ có cấu hình được biết đến. Bạn nên đọc phần chung trước, sau đó đọc về các yêu cầu đối với một ngôn ngữ cụ thể. Xin lưu ý thêm về phần thực thi từ xa, phần này yêu cầu một số điểm cần cân nhắc bổ sung.

Mặc dù có thể tuỳ chỉnh nhiều, nhưng tài liệu này tập trung vào việc tạo và sử dụng lcov báo cáo, đây hiện là phương thức được hỗ trợ tốt nhất.

Tạo báo cáo mức độ sử dụng

Chuẩn bị

Quy trình làm việc cơ bản để tạo báo cáo mức độ sử dụng yêu cầu những điều sau:

  • Một kho lưu trữ cơ bản có mục tiêu kiểm thử
  • Một chuỗi công cụ đã cài đặt các công cụ mức độ sử dụng mã dành riêng cho ngôn ngữ
  • Cấu hình "instrumentation" chính xác

Hai điều kiện đầu tiên là dành riêng cho ngôn ngữ và hầu hết đều đơn giản, tuy nhiên, điều kiện thứ hai có thể khó hơn đối với các dự án phức tạp.

"Instrumentation" trong trường hợp này đề cập đến các công cụ mức độ sử dụng được dùng cho một mục tiêu cụ thể. Bazel cho phép bật tính năng này cho một tập hợp con cụ thể của các tệp bằng cách sử dụng cờ --instrumentation_filter, cờ này chỉ định một bộ lọc cho các mục tiêu được kiểm thử khi bật tính năng instrumentation. Để bật tính năng instrumentation cho các bài kiểm thử, bạn cần có cờ --instrument_test_targets.

Theo mặc định, bazel cố gắng khớp(các) gói mục tiêu và in bộ lọc liên quan dưới dạng thông báo INFO.

Chạy mức độ sử dụng

Để tạo báo cáo mức độ sử dụng, hãy sử dụng bazel coverage --combined_report=lcov [target]. Lệnh này chạy các bài kiểm thử cho mục tiêu, tạo báo cáo mức độ sử dụng ở định dạng lcov cho mỗi tệp.

Sau khi hoàn tất, bazel sẽ chạy một hành động thu thập tất cả các tệp mức độ sử dụng đã tạo và hợp nhất chúng thành một tệp. Tệp này sẽ được tạo trong $(bazel info output_path)/_coverage/_coverage_report.dat.

Báo cáo mức độ sử dụng cũng được tạo nếu các bài kiểm thử không đạt, mặc dù lưu ý rằng điều này không áp dụng cho các bài kiểm thử không đạt – chỉ các bài kiểm thử đạt mới được báo cáo.

Xem mức độ sử dụng

Báo cáo mức độ sử dụng chỉ được xuất ở định dạng không thể đọc được lcov. Từ đó, chúng ta có thể sử dụng tiện ích genhtml (một phần của dự án lcov) để tạo báo cáo có thể xem được trong trình duyệt web:

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

Xin lưu ý rằng genhtml cũng đọc mã nguồn để chú thích mức độ sử dụng bị thiếu trong các tệp này. Để hoạt động, dự kiến sẽ được thực thi trong thư mục gốc của dự án bazel. genhtml

Để xem kết quả, bạn chỉ cần mở tệp index.html được tạo trong thư mục genhtml trong bất kỳ trình duyệt web nào.

Để được trợ giúp và biết thêm thông tin về công cụ genhtml hoặc định dạng mức độ sử dụng lcov , hãy xem dự án lcov.

Thực thi từ xa

Việc chạy với tính năng thực thi kiểm thử từ xa hiện có một số lưu ý:

  • Hành động kết hợp báo cáo chưa thể chạy từ xa. Lý do là vì Bazel không coi các tệp đầu ra mức độ sử dụng là một phần của biểu đồ (xem vấn đề này), do đó, không thể xử lý chính xác các tệp này dưới dạng dữ liệu đầu vào cho hành động kết hợp. Để giải quyết vấn đề này, hãy sử dụng --strategy=CoverageReport=local.
    • Lưu ý: Bạn có thể cần chỉ định một nội dung như --strategy=CoverageReport=local,remote thay vì nếu Bazel được thiết lập để thử local,remote, do cách Bazel phân giải các chiến lược.
  • --remote_download_minimal và các cờ tương tự cũng không thể được sử dụng do hậu quả của cờ trước đó.
  • Bazel hiện sẽ không tạo được thông tin mức độ sử dụng nếu các bài kiểm thử đã được lưu vào bộ nhớ đệm trước đó. Để giải quyết vấn đề này, --nocache_test_results có thể được đặt dành riêng cho các lượt chạy mức độ sử dụng, mặc dù điều này chắc chắn sẽ gây ra chi phí lớn về thời gian kiểm thử.
  • --experimental_split_coverage_postprocessing--experimental_fetch_all_coverage_outputs
    • Thông thường, mức độ sử dụng được chạy như một phần của hành động kiểm thử, vì vậy, theo mặc định, chúng ta không nhận được tất cả mức độ sử dụng dưới dạng đầu ra của quá trình thực thi từ xa theo mặc định. Các cờ này ghi đè giá trị mặc định và thu thập dữ liệu mức độ sử dụng. Xem vấn đề này để biết thêm thông tin.

Cấu hình dành riêng cho ngôn ngữ

Java

Java sẽ hoạt động ngay khi sử dụng cấu hình mặc định. Các chuỗi công cụ bazel cũng chứa mọi thứ cần thiết cho quá trình thực thi từ xa, bao gồm cả JUnit.

Python

Điều kiện tiên quyết

Việc chạy mức độ sử dụng bằng Python có một số điều kiện tiên quyết:

Sử dụng coverage.py đã sửa đổi

Một cách để thực hiện việc này là thông qua rules_python. Cách này cho phép bạn sử dụng tệp requirements.txt. Các yêu cầu được liệt kê trong tệp sẽ được tạo dưới dạng mục tiêu bazel bằng quy tắc kho lưu trữ pip_install.

requirements.txt phải có mục sau:

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

Sau đó, bạn nên sử dụng tệp rules_python, pip_installrequirements.txt trong tệp WORKSPACE như sau:

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

Sau đó, các mục tiêu kiểm thử có thể sử dụng yêu cầu coverage.py bằng cách đặt nội dung sau trong các tệp 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",
    ],
)

Nếu đang sử dụng chuỗi công cụ Python khép kín, thay vì thêm phần phụ thuộc mức độ sử dụng vào mọi mục tiêu py_test, bạn có thể thêm công cụ mức độ sử dụng vào cấu hình chuỗi công cụ.

Vì quy tắc pip_install phụ thuộc vào chuỗi công cụ Python, nên bạn không thể dùng quy tắc này để tìm nạp mô-đun coverage. Thay vào đó, hãy thêm vào WORKSPACE ví dụ:

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

Sau đó, hãy định cấu hình chuỗi công cụ Python như ví dụ:

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