RustRover 中的防銹單元和集成測試

https://blog.jetbrains.com/rust/2024/04/02/rust-unit-and-integration-testing-in-rustrover/

RustRover 中的 Rust 單元和整合測試

本文旨在探討如何最大程度地提高 Rust 項目的測試效率,包括單元測試和整合測試。同時也將研究如何在 RustRover 中運行和調試測試,從而提高軟體質量和生產力。您將成為一位測試專家。

建議下載最新版本的 RustRover,體驗 Rust 中的單元測試。

專案架構

Rust 具有靈活的專案結構,從非常簡單到極其複雜不等,這使得 Rust 成為構建各種解決方案的極佳選擇。我們建議您充分利用 crate,這樣可以更輕鬆地編寫整合測試,同時也有助於分離單元測試。在討論專案結構之前,讓我們先了解一下單元測試和整合測試之間的區別。

單元測試 vs. 整合測試

一般來說,單元測試的目的是在應用程式內部驗證程式碼。根據《Rust Book》的說法:

“單元測試的目的是獨立於其他程式碼測試每個程式碼單元,以快速找出程式碼是否符合預期。”

-《Rust Book》

那麼整合測試呢?它們是做什麼的,與單元測試有何區別?

“整合測試完全與您的庫無關,並以與任何其他外部程式碼相同的方式使用您的程式碼,僅使用公共介面,並可能對多個模組進行測試。”

–《Rust Book》

整合測試允許您測試多個 crate 之間的互動,強調了黑盒測試,著重於用戶公共 API 和調用函數返回的結果。您也可以進行一些初始的測試前準備,例如清除目錄、設置數據庫或創建共享資源。

於是,我們回到專案並查看目錄結構。

Crate 是偉大的!

這部分將提供一般性指南,以便為二進制、庫和整合測試設置 crate。讓我們首先查看最終的結構並分解各個部分。

第一步是在 Cargo.toml 文件中創建一個根目錄。此文件的內容將管理專案的工作區。在這篇文章的情況下,工作區包含兩個庫和一個二進制 crate。

[workspace]
members = []
resolver = “2”

使用 RustRover,您現在可以為主要創建一個二進制 crate,並為 process 和 integration_tests 創建兩個 crate 庫。

文件的最終內容應該如下.

[workspace]
members = [ “main”,”process”, “integration_tests”]
resolver = “2”

再來一步是在 integration_tests crate 下創建一個 tests 目錄。Rust 將這視為整合測試的保留文件夾名稱。

另一條是使用以下依賴塊將我們的 process 庫連接到 integration 測試和二進制 capital。

[dependencies]
process = { path = “../process” }

我們準備工作。請注意,您的專案可能需要多個或少量的整合測試 crate。有時,您甚至可能不需要它們,但至少在需要時擁有一個是令人愉悅的。

模組中的單元測試

我在 process crate 中實珽了一些計算器運算,例如 add(加法)、subtract(減法)、multiply(乘法)和 divide(除法)。我將它們放在該 crate 的 src 目錄下的 methods 模組文件中。

Rust 一般的單元測試哲學是將任何單元測試放置在實珽盡可能靠近實珽的位置,通常可以在程式碼存在的位置添加單元測試。

在文件底部,您可以使用 RustRover 的 tmod live template 來創建 tests 模組。

這將生成以下範本代碼。

#[cfg(test)]
mod tests {
use super::*;

}

在這裡,我們可以撰寫測試。我們可以使用測試屬性裝飾所有測試,並且函數主體使用 Rust 中包含的 assert 變體,例如 assert_eq!、assert!和 assert_neq!。use super*一行允許我們的 tests 模組引用父模組中的所有函數,包括我們的計算器運算。我們也可以使用 should_panic 屬性測試失敗場景。最後,所有 println!用法將顯示標準輸出。

要創建單獨的測試,您也可以使用 tfn 的 live template 創建單獨測試的範本。

讓我們更新文件以包含所有我們的新測試。

現在我們有了一些單元測試,讓我們轉移到一些整合測試。

在獨立 crate 中的整合測試

如先前所述,整合測試存在於 crate 之外,主要是用於驗證公共 API 和各 crate 之間的互動。對於本專案,我創建了一個 execute 函數,該函數處理傳遞給我們應用程序的命令行參數。

// process/src/lib.rs
use crate::methods::*;

pub mod methods;

pub fn execute(args: Vec) -> i32 {

if args.len() < 4 { panic!("incorrect amount of arguments: {:?}", args) } let _app_path = args[0].to_string(); let method = args[1].parse().unwrap(); let a = args[2].parse().unwrap_or_default(); let b = args[3].parse().unwrap_or_default(); let result = match method { OperationKind::Add => add(a, b),
OperationKind::Subtract => subtract(a, b),
OperationKind::Multiply => multiply(a, b),
OperationKind::Divide => divide(a, b),
};

println!(“{} + {} = {}”, a, b, result);
result
}

此函數抽象了主要二進制 crate 中使用的邏輯。

// main/src/main.rs
​​extern crate process;

use std::env;
use process::execute;

fn main() {
let args: Vec = env::args().collect();
execute(args);
}

雖然我可以在主要的 crate 中放置單元測試,但由於它與命令行參數的互動,我將其包含在 integration_tests crate 中。您應該根據您自己的判斷和判斷力決定測試的放置位置。

在我的 integration_tests crate 中,我創建了兩個模組,common/mod.rs 和 main_tests.rs。

common 模組是介於整合測試之間的可重複使用的功能。在我的案例中,這僅是一個簡單的 println!。

在 main_tests 中,您預計會看到 execute 的整合測試。請注意,我們只能訪問我們的 process crate 中找到的公共 API。

進行測試是使用相同的機制,所以它們看起來很相似。

執行測試

所以我們寫了所有這些測試,但我們該如何運行它們呢?在 RustRover 中,您可以通過線條圖示執行單個測試、測試模組或在 crate 或專案中找到的整個測試套件。還有一個 Run All Tests 功能,可以通過右鍵單擊 crate 並從上下文菜單中選擇它來找到。

RustRover 會將測試工具窗口中的結果分為通過和失敗組。此外,您將在測試過程中看到所有 println!調用。

您還可以選擇 Rerun Automatically 功能,在程式碼更改時運行所有測試,或僅選擇 Rerun Failed Tests 來在程式設計會話期間針對失敗的測試進行調試。

測試調試

盡管我們所看到的測試相對簡單,但有時測試可能失敗,了解“為什麼?”可能會很麻煩。

使用 RustRover,您可以設置斷點並逐步執行測試。使用 RustRover 的調試器,您可以查看作用域中的變數及其值。您還可以評估運算式,添加觀察以簡化信息可視性並導航呼叫堆疊。調試器是一個強大的工具,可幫助您消除煩人的錯誤並恢復生產力。

結論

正如您在本文中所見,以特定方式設置您的專案目錄可以讓您為測試成功做好準備。用 crate 考慮您的解決方案,有助於您選擇模組應放在哪裡以及如何構建您的私有和公共 API。無論您更偏好單元測試、整合測試還是組合,RustRover 都能幫助您編寫和運行它們。如果您對特定測試有困難,請記住所有測試都可以在調試器下運行,這將為您提供比 println!調用更多的洞察力。

請在下方留下您的評論和問題。同時,千萬不要錯過下載和嘗試 RustRover。我們相信您會喜歡它。

via JetBrains Company Blog

April 3, 2024 at 01:42AM

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *