如何生成 Rust 代碼覆蓋率

代碼覆蓋率是一個至關重要的度量標準,它可以很好地洞察軟件質量。代碼覆蓋率通常以百分比表示,並提供有關軟件的多少代碼被一組單元測試或測試套件測試。把它想象成一個文本高亮工具,它顯示代碼的哪些部分經過測試,哪些部分可以考慮進行進一步測試,以提高代碼的質量。

更高的代碼覆蓋率增加了對代碼功能的信心,並降低了 bug 的風險。大多數代碼覆蓋工具都可以集成到 CI 管道中,這樣代碼覆蓋就可以隨着代碼的增長而不斷改進。在一些項目中,代碼覆蓋需求包含在合併策略中,以確保軟件質量。由於代碼覆蓋工具還報告了測試套件未測試的代碼區域,因此它有助於確定測試的重點區域。在某些安全至關重要的受監管領域,如汽車、航空航天和醫療保健,就更需要代碼覆蓋信息。

有多種方法可以用來評估測試軟件的代碼覆蓋率,如下所述。

1,語句覆蓋率: 儘管更流行的術語是行覆蓋,但在許多語言中,一行中可能有多條語句,因此純粹主義者更喜歡使用語句覆蓋。如果一條語句在運行測試套件時至少執行一次,則認爲它已被覆蓋。

2,區域覆蓋率: 它是已執行的代碼區域的百分比,代碼區域可以跨越由多個語句組成的多行,例如函數體。

3,分支覆蓋率: 分支覆蓋率是軟件測試中使用的一個度量,用於評估一組測試用例執行了程序控制流中的多少分支或決策點。在代碼覆蓋率分析的上下文中,“分支”通常指的是代碼中的一個決策點,程序可以根據條件 (例如,if 語句或 switch 語句) 採取不同的路徑。

4,MC/DC 覆蓋率: 修改條件 / 決策覆蓋 (Modified Condition/Decision coverage, MC/DC) 是一種用於關鍵安全系統的嚴格的軟件測試技術。它確保代碼中的每個決策都在所有可能的結果下進行了測試,並且決策中的每個條件都可以獨立地影響決策的結果。MC/DC 的優勢在於它的效率。它提供了高水平的故障檢測,同時比完全條件覆蓋所需的測試用例更少。

在這篇文章中,我們將討論如何爲 Rust 應用程序生成代碼覆蓋信息。我們還將討論與支持代碼覆蓋相關的 Rust 編譯器未來版本的當前狀態和特性。Rust 使用 LLVM 作爲編譯後端。相應地,Rust 編譯器利用了 LLVM 提供的一些檢測覆蓋特性。隨着在 LLVM 中添加相應的功能,Rust 中的支持代碼覆蓋的功能有望增長。我們將簡要討論 Rust 編譯器對 LLVM 代碼覆蓋特性的依賴。

在 Rust 中啓用代碼覆蓋

Rust 中的代碼覆蓋率數據可以通過以下兩種方法收集:

1,使用 - Z profile 命令標誌

這使用了與 gcc 兼容的基於 gcov 的覆蓋實現。簡單來說,它可以幫助你收集基於 DebugInfo 的覆蓋率數據。當你想要查看代碼的哪些部分正在執行,哪些部分沒有執行時,這是非常方便的,這就像有一個代碼執行的路線圖。

2. 使用 - C instrument-coverage 命令標誌

此標誌啓用 LLVM 的本機覆蓋檢測,它以其效率和精度而聞名。它提供了高度精確的覆蓋率數據,可以檢查正在執行的代碼的確切部分。這對於識別未被測試的代碼區域非常有用。因此,當你希望使用高度精確的數據來提高測試的健壯性時,可以選擇基於 -C instrument-coverage 的覆蓋工具。

在本文中,我們將詳細討論 -C instrument-coverage 標誌,它更廣泛地用於基於源代碼的代碼覆蓋。

下面的簡單示例說明了這是如何工作的。

pub fn is_even(nu32) -> bool {
    if n % 2 == 0 {
        true
    } else {
        false
    }
}

測試代碼如下:

#[test]
pub fn test_even() {
    assert_eq!(is_even(2), true);
}

爲了啓用代碼覆蓋,我們在用 Rust 編譯器編譯程序時使用 -C instrument-coverage 標誌。

如果我們使用 Cargo 來構建程序,我們可以通過設置 RUSTFLAGS 環境變量啓用這個標誌,如下所示。

RUSTFLAGS="-Cinstrument-coverage" cargo test

這將產生所謂的 “儀表化” 二進制 / 可執行文件,其中注入了額外的代碼來計算行、區域和分支。

實際上發生的事情是編譯器注入如下所示的計數器增量來跟蹤計數:

pub fn is_even(nu32) -> bool {
    is_even_counter += 1;

    if n % 2 == 0 {
        is_even_true_branch_counter += 1;
        true
    } else {
        is_even_false_branch_counter += 1;
        false
    }
}

因此,每當輸入特定的功能 / 區域或分支時,相關的計數器就會增加。所有這些計數器都存儲在程序內存中的特定位置。

除此之外,一個額外的運行時也被注入到二進制文件中,它在程序的整個生命週期中初始化和管理這些計數器 (稱爲 LLVM 分析器運行時)。

pub fn main() {
    __initialize_counters();

    test_even(); 

    //Other tests….
    __write_counter_data_to_file();
}

當程序退出時,來自這些計數器的原始數據被寫入 “profraw” 文件,該文件可用於創建覆蓋率報告。

Rust 中的代碼覆蓋工具

下面是在 Rust 中流行的覆蓋工具:

1,Tarpaulin: Tarpaulin 是一個免費的 Rust 庫,提供源代碼行覆蓋功能。它仍處於開發的早期階段,但它已經被證明是測試 Rust 應用程序的一個好選擇。

2,grcov: grcov 是一個免費的庫,它收集和聚合項目中所有 Rust 文件的代碼覆蓋率信息,在內部使用 llvm-cov 來創建報告。

3,cargo-llvm-cov: 這是 Rust 代碼覆蓋的另一個流行工具。

使用 cargo-tarpaulin

Cargo-tarpaulin 是 Rust 生態系統中收集代碼覆蓋率數據的流行工具,它被設計成與 cargo 構建系統一起使用。下面是一個簡單的例子,告訴你如何使用 cargo-tarpaulin:

# 安裝 cargo-tarpaulin
cargo install cargo-tarpaulin

# 運行 cargo-tarpaulin 收集覆蓋率數據
cargo tarpaulin

結果如下:

INFO cargo_tarpaulin::statemachine::instrumented: For binary: target/debug/deps/code_covrage-4e2873bf50ec5596
INFO cargo_tarpaulin::statemachine::instrumented: Generated: target/tarpaulin/profraws/code_covrage-4e2873bf50ec5596_16540310165768346208_0-50218.profraw
INFO cargo_tarpaulin::statemachine::instrumented: Merging coverage reports
INFO cargo_tarpaulin::statemachine::instrumented: Mapping coverage data to source
INFO cargo_tarpaulin::report: Coverage Results:
|| Uncovered Lines:
|| src/main.rs: 5, 9
|| Tested/Total Lines:
|| src/main.rs: 3/5
|| 
60.00% coverage, 3/5 lines covered

在這個例子中,cargo-tarpaulin 將在控制檯中自動生成報告,對於更詳細的報告,cargo-tarpaulin 支持多種輸出格式,如 Json、Xml 和 Html。

使用 grcov

Grcov 是一個從測試套件中收集和聚合代碼覆蓋率數據的 Rust 工具。當你想要將代碼覆蓋率報告集成到持續集成管道中時,它特別有用。下面是如何在 Rust 項目中使用 grcov 的一個簡單示例:

# 安裝 grcov
cargo install grcov

# 運行測試
RUSTFLAGS="-Cinstrument-coverage" cargo test

# 生成覆蓋率報告
grcov . -s . --binary-path ./target/debug/ -t html --ignore tests/  -o ./target/debug/coverage/

# 在瀏覽器中打開HTML文件查看報告
open target/debug/coverage/index.html

下圖顯示了一個示例覆蓋率報告。我們可以找到項目中每個 Rust 模塊的覆蓋信息,如行覆蓋、函數覆蓋和分支覆蓋。

使用 cargo-llvm-cov

Cargo-llvm-cov 是一個 Rust 工具,它利用 LLVM 基於源代碼的代碼覆蓋率來生成詳細的覆蓋率報告。下面是一個簡單的例子,說明如何在 Rust 項目中使用 cargo-llvm-cov。

# 安裝 cargo-llvm-cov
cargo install cargo-llvm-cov

# 運行有覆蓋率的測試
cargo llvm-cov

這將在控制檯中生成詳細的覆蓋率報告,結果如下:

Filename                        Regions    Missed Regions     Cover   Functions  Missed Functions  Executed       Lines      Missed Lines     Cover    Branches   Missed Branches     Cover
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
../code-covrage/src/main.rs           8                 2    75.00%           4                 1    75.00%          10                 2    80.00%           0                 0         -
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
TOTAL                                 8                 2    75.00%           4                 1    75.00%          10                 2    80.00%           0                 0         -

總結

代碼覆蓋率爲評估和改進源代碼的質量提供了非常有用的信息。Rust 已經爲諸如行覆蓋、函數覆蓋等特性提供了很好的支持。雖然 LLVM 支持分支覆蓋和 MC/DC 覆蓋,但仍有一些功能有待添加。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/VL3R318XNygQjbsDvYonxQ