首页 > 解决方案 > 有没有一种简单的方法可以有条件地启用或忽略 Rust 中的整个测试套件?

问题描述

我正在开发一个提供对某些硬件设备的访问的 Rust 库。有两种设备类型,1 和 2,类型 2 的功能是类型 1 功能的超集。

我想针对不同的情况提供不同的测试套件:

我正在使用特性来表示这种行为:默认特性test-no-device和可选特性test-type-one以及test-type-two. 然后我使用该cfg_attr属性忽略基于所选功能的测试:

#[test]
#[cfg_attr(not(feature = "test-type-two"), ignore)]
fn test_exclusive() {
    // ...
}

#[test]
#[cfg_attr(not(any(feature = "test-type-two", feature = "test-type-one")), ignore)]
fn test_shared() {
    // ...
}

这相当麻烦,因为我必须为每个测试复制这个条件,而且这些条件很难阅读和维护。

有没有更简单的方法来管理测试套件?

我在声明模块时尝试设置ignore属性,但显然它只能为每个test函数设置。我想我可以通过在模块上使用来禁用排除测试的cfg编译,但由于测试应该始终编译,我想避免这种情况。

标签: unit-testingrust

解决方案


有没有一种简单的方法可以有条件地启用或忽略 Rust 中的整个测试套件?

简单的是甚至不编译测试:

#[cfg(test)]
mod test {
    #[test]
    fn no_device_needed() {}

    #[cfg(feature = "test1")]
    mod test1 {
        fn device_one_needed() {}
    }

    #[cfg(feature = "test2")]
    mod test2 {
        fn device_two_needed() {}
    }
}

我必须为每个测试复制这个条件,而且这些条件很难阅读和维护。

  1. 你能用纯 Rust 表示所需的功能吗?是的
  2. 现有的语法是否过于冗长?是的

这是宏的候选对象。

macro_rules! device_test {
    (no-device, $name:ident, {$($body:tt)+}) => (
        #[test]
        fn $name() {
            $($body)+
        }
    );
    (device1, $name:ident, {$($body:tt)+}) => (
        #[test]
        #[cfg_attr(not(feature = "test-type-one"), ignore)]
        fn $name() {
            $($body)+
        }
    );
    (device2, $name:ident, {$($body:tt)+}) => (
        #[test]
        #[cfg_attr(not(feature = "test-type-two"), ignore)]
        fn $name() {
            $($body)+
        }
    );
}

device_test!(no-device, one, {
    assert_eq!(2, 1+1)
});

device_test!(device1, two, {
    assert_eq!(3, 1+1)
});

类型 2 的功能是类型 1 的功能的超集

在您的功能定义中反映这一点以简化代码:

[features]
test1 = []
test2 = ["test1"]

如果你这样做,你不应该需要在你anyall配置属性中。

默认功能test-no-device

这似乎没有用;而是使用由正常测试配置保护的正常测试:

#[cfg(test)]
mod test {
    #[test]
    fn no_device_needed() {}
}

如果你遵循这个,你可以从宏中删除这个案例。


我认为如果您遵循这两个建议,您甚至不需要宏。


推荐阅读