[英]Rust: Attribute #[cfg(test)] in crates with lib and binary targets
我目前正在開發一個Rust 項目,它有一個庫目標和一個二進制目標。
該庫定義了兩個緊急處理程序,一個用於生產用途,一個用於測試,它們是使用 #[cfg(test)] 屬性有條件地編譯的。 這對於單元測試 src/lib.rs 工作正常,但是一旦在測試/(或 src/main.rs)中進行集成測試,“生產”恐慌處理程序就會鏈接到,即在這些情況下,lib。 rs 使用 test=false 編譯。
有什么方法可以防止/配置它嗎?
使用以下目錄結構可重現性極低:
Cargo.toml
src/lib.rs
src/main.rs
清單如下所示:
# Cargo.toml
...
[lib]
name = "kernel"
[[bin]]
path = "src/main.rs"
name = "titanium"
二進制代碼:
// main.rs
fn main() {
println!("Hello, world!");
}
#[test]
fn it_works() {
assert_eq!(kernel::hello(), "Hello!".to_string());
}
...對於圖書館:
// lib.rs
#[cfg(test)]
pub fn hello() -> String {
"Hello!".to_string()
}
#[cfg(not(test))]
pub fn hello() -> String {
"Goodbye!".to_string()
}
#[test]
fn it_works() {
assert_eq!(hello(), "Hello!".to_string())
}
回答上述行為實際上適用於大約 99% 的用例,但是,我的不是其中之一。
對於我的用例(在“無頭”VM 中運行的玩具操作系統的測試套件,即僅輸出到主機的標准輸出)我最終定義了一個功能來切換恐慌處理程序。 適應上面的例子,它現在看起來像這樣:
# Cargo.toml
...
[features]
test_qemu_headless = []
然后二進制文件保持不變,在庫中我做
// lib.rs
#[cfg(feature = "test_qemu_headless")]
pub fn hello() -> String {
"Hello!".to_string()
}
#[cfg(not(feature = "test_qemu_headless"))]
pub fn hello() -> String {
"Goodbye!".to_string()
}
#[test]
fn it_works() {
assert_eq!(hello(), "Hello!".to_string())
}
然后運行測試
cargo test --features test_qemu_headless
lib 目標被編譯兩次:一次是在運行單元測試時; 在這里, #[cfg(test)]
處於活動狀態,因為 lib當前正在編譯為rustc --test
。 第二次運行集成測試時; 此處, #[cfg(test)]
未激活,因為 lib 正在正常編譯,然后鏈接到集成測試模塊,這些模塊本身被編譯為測試。 換句話說,當與集成測試一起使用時,lib 目標不知道它正在被編譯並在測試中使用(這在某種程度上是集成測試的重點)。
您正在尋找的是#[cfg(debug_assertions)]
來裝飾您的恐慌處理程序。 無論出於何種原因,只要代碼在“調試”模式下編譯,此屬性就會處於活動狀態。 使用此屬性,您的測試處理程序將對單元測試和集成測試都有效。
但是,如果您在“調試”模式下編譯 bin 目標並運行它(例如,通過沒有--release
cargo run
),或者如果您的庫依賴於以“調試”模式編譯的其他一些 crate,則測試-庫中的處理程序也將處於活動狀態,這可能不是您想要的。 如果是這樣,您需要為您的箱子定義一個feature
,依賴於您的恐慌處理程序的測試可以將其用作條件編譯的標志(例如foocrate_use_internal_dummy_panic_handler
)。 然后,您需要在運行測試時激活該功能 - 它成為全局旋鈕。 清單中還有一個required-feature
字段。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.