未预先执行cargo build时Rust CLI应用测试失败的解决办法
问题
我正在对一款纯Rust CLI应用做单元测试,执行以下命令时会弹出找不到二进制文件的错误:
cargo clean cargo test --release
但换成下面的命令就能正常运行:
cargo clean cargo build --release cargo test --release
有没有办法让Cargo自动先把二进制应用构建完成,再执行测试?
测试代码
#[cfg(test)] pub mod tests { use std::process::Command; use assert_cmd::prelude::{CommandCargoExt, OutputAssertExt}; use predicates::prelude::predicate; #[test] fn test_that_cli_app_produces_result() -> Result<(), Box<dyn std::error::Error>> { let mut cmd = Command::cargo_bin("fastsim-cli")?; let mut cyc_file = project_root::get_project_root().unwrap(); cyc_file.push("../fastsim/resources/cycles/udds.csv"); assert!(cyc_file.exists()); let mut veh_file = project_root::get_project_root().unwrap(); veh_file.push("../fastsim/resources/vehdb/2012_Ford_Fusion.yaml"); assert!(veh_file.exists()); cmd.args([ "--cyc-file", cyc_file.to_str().unwrap(), "--veh-file", veh_file.to_str().unwrap(), ]); cmd.assert() .success() .stdout(predicate::str::contains("32.4")); Ok(()) } }
解决方案
问题根源在于cargo test默认只会构建测试相关代码及依赖,不会自动触发CLI二进制目标的构建。以下几种方法可以解决这个问题:
方法1:测试时指定构建二进制目标
执行测试命令时,明确告诉Cargo要先构建对应的二进制:
cargo test --release --bin fastsim-cli
这条命令会优先构建fastsim-cli二进制,再运行测试。
方法2:修改Cargo.toml关联测试与二进制
在Cargo.toml中给测试目标添加对二进制的依赖,让Cargo自动先构建二进制:
[[test]] name = "your_test_module" # 对应代码中的测试模块名 dependencies = ["fastsim-cli"]
如果测试写在lib crate里,也可以直接在[lib]区块下添加依赖:
[lib] name = "fastsim_lib" path = "src/lib.rs" dependencies = ["fastsim-cli"]
方法3:使用--all-targets参数构建所有目标
这个参数会让Cargo构建所有类型的目标(二进制、库、测试等)后再执行测试:
cargo test --release --all-targets
缺点是会构建所有目标,可能比只构建需要的二进制更耗时。
方法4:测试代码中手动触发构建
在测试开头添加构建命令,强制Cargo先生成二进制:
#[test] fn test_that_cli_app_produces_result() -> Result<(), Box<dyn std::error::Error>> { // 先构建release版本的二进制 Command::new("cargo") .args(["build", "--release", "--bin", "fastsim-cli"]) .status()?; // 后续测试代码不变 let mut cmd = Command::cargo_bin("fastsim-cli")?; let mut cyc_file = project_root::get_project_root().unwrap(); cyc_file.push("../fastsim/resources/cycles/udds.csv"); assert!(cyc_file.exists()); let mut veh_file = project_root::get_project_root().unwrap(); veh_file.push("../fastsim/resources/vehdb/2012_Ford_Fusion.yaml"); assert!(veh_file.exists()); cmd.args([ "--cyc-file", cyc_file.to_str().unwrap(), "--veh-file", veh_file.to_str().unwrap(), ]); cmd.assert() .success() .stdout(predicate::str::contains("32.4")); Ok(()) }
这种方法会增加冗余构建,不如前几种优雅,适合临时场景。
内容的提问来源于stack exchange,提问作者Chad
相关产品推荐
相关产品推荐

