如何基于常量在Rust中条件编译测试用例?
问题
我定义了如下常量:
const SIZE: usize = 8;
我写了多组测试用例,有的针对SIZE大于8的场景,有的针对SIZE小于8的场景,用来验证特殊情况。比如某测试用到了u8类型,当SIZE大于8时根本没法运行。
我知道运行时没办法条件跳过测试,但所有信息都是编译期就能确定的,能不能用类似#[cfg(SIZE <= 8)]的语法,只在常量处于指定范围时编译对应的测试用例?
我的测试示例如下:
#[cfg(test)] mod test { use super::SIZE; #[test] fn will_panic_if_size_small() { assert!(SIZE > 8); } #[test] fn will_panic_if_size_big() { assert!(SIZE <= 8); } }
解决方案
直接用#[cfg(SIZE <= 8)]这种写法行不通,因为#[cfg]只能识别Rust内置的配置选项或自定义编译特征(feature),没法直接引用代码里的常量表达式。不过有几种方法能实现编译期条件编译测试的需求:
方法1:借助cfg_if crate配合常量判断
可以用cfg_if库结合编译期常量求值来实现,先在Cargo.toml里加依赖:
[dev-dependencies] cfg-if = "1.0"
然后修改测试代码:
use cfg_if::cfg_if; const SIZE: usize = 8; #[cfg(test)] mod test { use super::SIZE; cfg_if! { if SIZE <= 8 { #[test] fn size_big_test() { assert!(SIZE <= 8); // 这里放只有SIZE<=8时能编译的代码,比如用u8类型的逻辑 } } else { #[test] fn size_small_test() { assert!(SIZE > 8); // 这里放SIZE>8时的测试逻辑 } } } }
这种方式利用cfg_if的编译期代码展开特性,只保留符合常量条件的测试函数。
方法2:用compile_error!配合条件编译
不想加额外依赖的话,能用常量条件加compile_error!间接控制测试是否编译:
const SIZE: usize = 8; #[cfg(test)] mod test { use super::SIZE; // 仅当SIZE <=8时编译该测试 #[allow(unused)] const _: () = if !(SIZE <= 8) { compile_error!("这个测试只有在SIZE <=8时才能编译"); }; #[test] fn size_big_test() { assert!(SIZE <= 8); // SIZE<=8时的测试逻辑 } // 仅当SIZE >8时编译该测试 mod size_greater_8 { use super::*; #[allow(unused)] const _: () = if !(SIZE > 8) { compile_error!("这个测试只有在SIZE >8时才能编译"); }; #[test] fn size_small_test() { assert!(SIZE > 8); // SIZE>8时的测试逻辑 } } }
当常量条件不满足时,compile_error!会触发编译错误,对应的测试模块或函数就不会被编译,从而达到只保留符合条件测试的效果。
方法3:自定义编译特征(Feature)
如果SIZE的值是通过编译特征控制的(比如在Cargo.toml里定义不同feature来设置SIZE),可以直接用#[cfg(feature = "...")]控制测试:
先在Cargo.toml里定义:
[features] size-small = [] size-large = []
然后在代码中:
#[cfg(feature = "size-small")] const SIZE: usize = 4; #[cfg(feature = "size-large")] const SIZE: usize = 16; #[cfg(test)] mod test { use super::SIZE; #[cfg(feature = "size-small")] #[test] fn size_small_test() { assert!(SIZE <=8); } #[cfg(feature = "size-large")] #[test] fn size_large_test() { assert!(SIZE >8); } }
这种方式适合需要通过编译参数切换SIZE值的场景,用内置的cfg特征就能直接控制测试的编译。
内容的提问来源于stack exchange,提问作者Dumbo
相关产品推荐
相关产品推荐

