बेज़ेल के साथ कोड कवरेज

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 8.0 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel में coverage सब-कमांड होता है, जिसकी मदद से उन रिपॉज़िटरी के लिए कोड कवरेज की रिपोर्ट जनरेट की जा सकती हैं जिनकी जांच bazel coverage से की जा सकती है. अलग-अलग भाषा के सिस्टम के हिसाब से, किसी प्रोजेक्ट के लिए इसे इस्तेमाल करना हमेशा आसान नहीं होता.

इस पेज पर, कवरेज रिपोर्ट बनाने और देखने की सामान्य प्रोसेस के बारे में बताया गया है. साथ ही, उन भाषाओं के लिए कुछ खास नोट भी दिए गए हैं जिनका कॉन्फ़िगरेशन अच्छी तरह से जाना जाता है. इसे सबसे पहले सामान्य सेक्शन और फिर किसी खास भाषा की ज़रूरी शर्तों के बारे में पढ़कर पढ़ा जा सकता है. रिमोट तौर पर लागू करने के सेक्शन पर भी ध्यान दें. इसके लिए, कुछ और बातों का ध्यान रखना ज़रूरी है.

इस दस्तावेज़ में, lcov रिपोर्ट बनाने और उनका इस्तेमाल करने पर फ़ोकस किया गया है. फ़िलहाल, यह सबसे सही तरीका है. हालांकि, इसमें ज़रूरत के हिसाब से कई बदलाव किए जा सकते हैं.

कवरेज रिपोर्ट बनाना

वीडियो की रणनीति

कवरेज रिपोर्ट बनाने के बुनियादी वर्कफ़्लो के लिए, इन चीज़ों की ज़रूरत होती है:

  • टेस्ट टारगेट वाला बुनियादी रिपॉज़िटरी
  • भाषा के हिसाब से कोड कवरेज टूल इंस्टॉल किए गए टूलचेन
  • सही "इंस्ट्रूमेंटेशन" कॉन्फ़िगरेशन

पहले दो, भाषा के हिसाब से होते हैं और ज़्यादातर आसान होते हैं. हालांकि, जटिल प्रोजेक्ट के लिए, बाद वाला तरीका ज़्यादा मुश्किल हो सकता है.

इस मामले में, "इंस्ट्रूमेंटेशन" का मतलब कवरेज टूल से है, जिनका इस्तेमाल किसी खास टारगेट के लिए किया जाता है. Bazel, --instrumentation_filter फ़्लैग का इस्तेमाल करके, फ़ाइलों के किसी खास सबसेट के लिए इसे चालू करने की अनुमति देता है. यह उन टारगेट के लिए फ़िल्टर तय करता है जिनकी जांच, इंस्ट्रूमेंटेशन चालू होने पर की जाती है. टेस्ट के लिए इंस्ट्रूमेंटेशन चालू करने के लिए, --instrument_test_targets फ़्लैग ज़रूरी है.

डिफ़ॉल्ट रूप से, bazel टारगेट किए गए पैकेज से मैच करने की कोशिश करता है. साथ ही, काम के फ़िल्टर को INFO मैसेज के तौर पर प्रिंट करता है.

रनिंग कवरेज

कवरेज रिपोर्ट बनाने के लिए, bazel coverage --combined_report=lcov [target] का इस्तेमाल करें. यह टारगेट के लिए जांच करता है और हर फ़ाइल के लिए lcov फ़ॉर्मैट में कवरेज रिपोर्ट जनरेट करता है.

प्रोसेस पूरी होने के बाद, bazel एक कार्रवाई करता है. यह कार्रवाई, जनरेट की गई सभी कवरेज फ़ाइलों को इकट्ठा करके, उन्हें एक में मर्ज करता है. आखिर में, इसे $(bazel info output_path)/_coverage/_coverage_report.dat में बनाया जाता है.

टेस्ट पास न होने पर भी कवरेज रिपोर्ट जनरेट होती हैं. हालांकि, ध्यान दें कि यह उन टेस्ट पर लागू नहीं होता जो पास नहीं हुए हैं. सिर्फ़ पास हुए टेस्ट की ही रिपोर्ट जनरेट होती है.

कवरेज देखना

कवरेज रिपोर्ट सिर्फ़ ऐसे lcov फ़ॉर्मैट में आउटपुट होती है जिसे कोई व्यक्ति पढ़ नहीं सकता. इससे, हम genhtml यूटिलिटी (lcov प्रोजेक्ट का हिस्सा) का इस्तेमाल करके, ऐसी रिपोर्ट तैयार कर सकते हैं जिसे वेब ब्राउज़र में देखा जा सकता है:

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

ध्यान दें कि genhtml, सोर्स कोड को भी पढ़ता है, ताकि इन फ़ाइलों में मौजूद कोड को एनोटेट किया जा सके. यह काम करने के लिए, यह ज़रूरी है कि genhtml को bazel प्रोजेक्ट के रूट में चलाया जाए.

नतीजा देखने के लिए, किसी भी वेब ब्राउज़र में genhtml डायरेक्ट्री में बनाई गई index.html फ़ाइल खोलें.

genhtml टूल या lcov कवरेज फ़ॉर्मैट के बारे में ज़्यादा मदद और जानकारी पाने के लिए, lcov प्रोजेक्ट देखें.

रिमोट से चलाना

फ़िलहाल, रिमोट टेस्ट एक्सीक्यूशन की सुविधा का इस्तेमाल करने में कुछ सावधानियां बरतनी पड़ती हैं:

  • रिपोर्ट के कॉम्बिनेशन ऐक्शन को अभी तक रिमोट तौर पर नहीं चलाया जा सकता. ऐसा इसलिए होता है, क्योंकि Bazel, कवरेज आउटपुट फ़ाइलों को अपने ग्राफ़ के हिस्से के तौर पर नहीं मानता (यह समस्या देखें). इसलिए, वह उन्हें कॉम्बिनेशन ऐक्शन के इनपुट के तौर पर सही तरीके से इस्तेमाल नहीं कर सकता. इस समस्या को हल करने के लिए, --strategy=CoverageReport=local का इस्तेमाल करें.
    • ध्यान दें: अगर Bazel को local,remote आज़माने के लिए सेट अप किया गया है, तो हो सकता है कि इसके बजाय --strategy=CoverageReport=local,remote जैसा कुछ बताना ज़रूरी हो. ऐसा इसलिए, क्योंकि Bazel रणनीतियों को हल करने का तरीका अपनाता है.
  • --remote_download_minimal और मिलते-जुलते फ़्लैग का इस्तेमाल भी नहीं किया जा सकता.
  • अगर टेस्ट को पहले से कैश मेमोरी में सेव किया गया है, तो फ़िलहाल Bazel, कवरेज की जानकारी नहीं बना पाएगा. इस समस्या को हल करने के लिए, --nocache_test_results को खास तौर पर कवरेज रन के लिए सेट किया जा सकता है. हालांकि, इससे जांच में लगने वाले समय की लागत ज़्यादा हो जाती है.
  • --experimental_split_coverage_postprocessing और --experimental_fetch_all_coverage_outputs
    • आम तौर पर, कवरेज को टेस्ट ऐक्शन के हिस्से के तौर पर चलाया जाता है. इसलिए, डिफ़ॉल्ट रूप से, हमें रिमोट रन के आउटपुट के तौर पर सारा कवरेज वापस नहीं मिलता. ये फ़्लैग, डिफ़ॉल्ट सेटिंग को बदल देते हैं और कवरेज का डेटा हासिल करते हैं. ज़्यादा जानकारी के लिए, यह समस्या देखें.

भाषा के हिसाब से कॉन्फ़िगरेशन

Java

Java, डिफ़ॉल्ट कॉन्फ़िगरेशन के साथ बिना किसी समस्या के काम करना चाहिए. bazel टूलचेन में, रिमोट तौर पर प्रोग्राम चलाने के लिए ज़रूरी सभी चीज़ें मौजूद होती हैं. इनमें JUnit भी शामिल है.

Python

ज़रूरी शर्तें

Python में कवरेज चलाने के लिए, कुछ ज़रूरी शर्तें पूरी करनी होती हैं:

बदले गए coverage.py का इस्तेमाल करना

ऐसा करने का एक तरीका rules_python है. इससे requirements.txt फ़ाइल का इस्तेमाल करने की सुविधा मिलती है. इसके बाद, फ़ाइल में बताई गई ज़रूरी शर्तों को pip_install रिपॉज़िटरी नियम का इस्तेमाल करके, bazel टारगेट के तौर पर बनाया जाता है.

requirements.txt में यह एंट्री होनी चाहिए:

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

इसके बाद, rules_python, pip_install, और requirements.txt फ़ाइल का इस्तेमाल, WORKSPACE फ़ाइल में इस तरह किया जाना चाहिए:

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

इसके बाद, BUILD फ़ाइलों में ये सेट करके, जांच के टारगेट के लिए coverage.py की ज़रूरी शर्तों का इस्तेमाल किया जा सकता है:

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

अगर किसी हेर्मेटिक Python टूलचेन का इस्तेमाल किया जा रहा है, तो हर py_test टारगेट में कवरेज डिपेंडेंसी जोड़ने के बजाय, टूलचेन कॉन्फ़िगरेशन में कवरेज टूल जोड़ा जा सकता है.

pip_install नियम, Python टूलचैन पर निर्भर करता है. इसलिए, इसका इस्तेमाल coverage मॉड्यूल को फ़ेच करने के लिए नहीं किया जा सकता. इसके बजाय, अपना WORKSPACE जोड़ें. उदाहरण के लिए,

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

इसके बाद, अपनी Python टूलचेन को इस तरह कॉन्फ़िगर करें:

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