如何在Rust的main函数中调用测试模块内的open_door函数?
解决Rust中main函数调用tests模块函数的编译错误
错误原因
原代码中tests模块带有#[cfg(test)]属性,这个属性会让该模块仅在执行cargo test时才被编译。正常执行cargo run时,编译器不会编译这个模块,所以main函数里的use tests;会找不到对应的模块,从而抛出E0432: unresolved import错误。
解决方案
方案一:抽离可复用逻辑到主模块(推荐)
将open_door的核心逻辑从测试模块中抽离到主模块,让main和tests模块都能调用它,既保留测试功能,又符合Rust代码组织规范:
#[derive(Debug)] struct Door { is_open: bool, } impl Door { fn new(is_open: bool) -> Door { Door { is_open } } } trait Openable { fn open(&mut self); } impl Openable for Door { fn open(&mut self) { self.is_open = true } } // 抽离核心逻辑到主模块,供main和测试调用 pub fn open_door() { let mut door = Door::new(false); println!("1: {:?}", door); door.open(); println!("2: {:?}", door); assert!(door.is_open); } #[cfg(test)] mod tests { use super::*; #[test] fn test_open_door() { // 测试模块调用主模块的逻辑 open_door(); } } fn main() { println!("Hello, world!"); open_door(); // 直接调用主模块的函数 }
方案二:移除tests模块的条件编译属性(不推荐)
如果一定要保留tests模块的结构,可以移除#[cfg(test)]属性,让模块始终被编译。此时测试函数的#[test]属性仅在cargo test时生效,main函数可以正常调用模块内的函数:
#[derive(Debug)] struct Door { is_open: bool, } impl Door { fn new(is_open: bool) -> Door { Door { is_open } } } trait Openable { fn open(&mut self); } impl Openable for Door { fn open(&mut self) { self.is_open = true } } // 移除#[cfg(test)],模块始终被编译 mod tests { use super::*; #[test] pub fn open_door() { let mut door = Door::new(false); println!("1: {:?}", door); door.open(); println!("2: {:?}", door); assert!(door.is_open); } } fn main() { println!("Hello, world!"); tests::open_door(); // 现在可正常调用模块函数 }
方案对比
- 方案一:代码结构清晰,测试模块专注于验证逻辑,可复用代码与测试代码分离,符合Rust最佳实践。
- 方案二:虽然快速解决问题,但测试模块代码会始终存在于编译后的程序中,不符合测试代码隔离的常规原则,仅适合临时调试场景。
内容的提问来源于stack exchange,提问作者Ayush Bindlish
相关产品推荐
相关产品推荐

