Rust如何在编译时统计crate内被#[test]注解的测试函数数量
Rust 集成测试自动统计测试总数方案
方案1:使用自定义测试框架(Nightly Rust)
这是最直接的官方支持方案,无需手动维护测试计数:
- 在集成测试文件顶部开启对应特性:
#![feature(custom_test_frameworks)] #![test_runner(crate::test_runner)]
- 实现自定义测试运行器,可直接获取当前测试二进制下所有测试的完整列表,自动拿到总数:
use test::{TestDesc, TestFn, TestDescAndFn}; fn test_runner(tests: &[&TestDescAndFn]) { // 直接拿到测试总数,无需手动统计 let test_count = tests.len(); // 初始化你的TestRunner,直接传入test_count let runner = TestRunner::new(test_count); // 执行crate级setup runner.crate_setup(); // 运行所有测试(原生支持并行、过滤、忽略等逻辑) test::run_tests_console(&test::TestOpts::default(), tests.to_vec()).unwrap(); // 所有测试执行完成后直接执行crate级teardown,不需要判断是否是最后一个测试 runner.crate_teardown(); }
这个方案完全规避了计数问题,清理逻辑执行时机100%准确,不需要依赖dtor之类的不稳定特性。
方案2:稳定Rust下使用自定义测试宏+全局收集
如果你需要使用稳定版Rust,可以用proc-macro实现自定义测试属性,自动收集测试数量:
- 新建proc-macro库,实现
#[integration_test]属性宏,功能包括:- 给每个标注的测试函数自动生成调用
TestRunner::run_test的包裹逻辑 - 用分布式静态切片机制将所有测试元信息全局收集,编译期自动统计总数
- 给每个标注的测试函数自动生成调用
- 集成测试中直接用
#[integration_test]替代原生#[test]即可,新增、删除、忽略测试都会自动更新总计数,无需手动修改任何参数
示例伪代码:
// 你的测试工具库中 #[linkme::distributed_slice] pub static TESTS: [fn()] = [..]; #[proc_macro_attribute] pub fn integration_test(_attr: TokenStream, item: TokenStream) -> TokenStream { // 解析原测试函数 let input = parse_macro_input!(item as ItemFn); let fn_name = &input.sig.ident; quote! { #input #[linkme::distributed_slice(crate::test_utils::TESTS)] #[linkme(crate = linkme)] static __TEST: fn() = || { crate::TEST_RUNNER.run_test(#fn_name); }; #[test] fn #fn_name() { __TEST(); } }.into() } // 测试运行器初始化时直接拿总数 lazy_static! { pub static ref TEST_RUNNER: TestRunner = TestRunner::new(TESTS.len()); }
这个方案完全兼容稳定Rust,开发者不需要手动维护测试计数,所有操作自动完成。
额外说明
如果你的需求只是要在所有测试结束后执行清理,其实不需要统计测试总数,方案1的自定义测试运行器可以直接在所有测试执行完成后统一调用teardown,是最稳妥的实现方式,完全避免了并行测试、忽略测试带来的计数误差问题。
内容的提问来源于stack exchange,提问作者David Sackstein
相关产品推荐
相关产品推荐

