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

Bazel có một lệnh con coverage để tạo báo cáo về 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 đặc thù của các hệ sinh thái ngôn ngữ khác nhau, việc triển khai phương pháp này cho một dự án nhất định không phải lúc nào cũng là đơn giản.

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

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 báo cáo lcov. Đây hiện là tuyến được hỗ trợ tốt nhất.

Tạo báo cáo mức độ phù hợp

Chuẩn bị

Quy trình làm việc cơ bản để tạo báo cáo mức độ phù hợp yêu cầu những thông tin sau:

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

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

Trong trường hợp này, "Đo lường" là các công cụ đo lườ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ác tệp cụ thể bằng cách sử dụng cờ --instrumentation_filter. Cờ này chỉ định bộ lọc cho các mục tiêu được kiểm thử khi bật tính năng đo lường. Để bật tính năng đo lường cho kiểm thử, bạn bắt buộc phải gắn cờ --instrument_test_targets.

Theo mặc định, bazel sẽ 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.

Mức độ phù hợp đang chạy

Để tạo báo cáo mức độ phù hợp, hãy sử dụng bazel coverage --combined_report=lcov [target]. Thao tác này sẽ 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 từng tệp.

Sau khi hoàn tất, bazel chạy một thao tác thu thập tất cả các tệp bảo hiểm đã tạo rồi hợp nhất các tệp này thành một, sau đó cuối cùng sẽ được tạo trong $(bazel info output_path)/_coverage/_coverage_report.dat.

Báo cáo phạm vi cũng được tạo nếu kiểm thử không thành công, tuy nhiên lưu ý rằng báo cáo này không bao gồm các kiểm thử không thành công – chỉ các kiểm thử đạt mới được báo cáo.

Phạm vi xem

Báo cáo mức độ sử dụng chỉ được xuất ở định dạng lcov không con người đọc được. 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 độ phù hợp bị thiếu trong các tệp này. Để tác vụ này hoạt động, dự kiến genhtml sẽ được thực thi trong thư mục gốc của dự án bazel.

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

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

Thực thi từ xa

Hiện tại, quá trình chạy thử nghiệm từ xa có một số lưu ý:

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

Cấu hình theo ngôn ngữ cụ thể

Java

Java phải hoạt động ngay lập tức với cấu hình mặc định. Chuỗi công cụ Bazel chứa mọi thứ cần thiết để thực thi từ xa, bao gồm cả JUnit.

Python

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

Để chạy mức độ bao phủ bằng python, bạn cần đáp ứng một số điều kiện tiên quyết:

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

Cách thực hiện việc này là thông qua rules_python. Quy tắc này cho phép sử dụng tệp requirements.txt, các yêu cầu liệt kê trong tệp sau đó sẽ được tạo dưới dạng mục tiêu bazel bằng cách sử dụ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 đó, tệp rules_python, pip_installrequirements.txt sẽ được dùng trong tệp WORKSPACE dưới dạng:

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 thiết lập như 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ể sử dụng quy tắc này để tìm nạp mô-đun coverage. Thay vào đó, hãy thêm WORKSPACE vào, 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 của bạn, 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",
)