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

Rob*_*ahl 5 unit-testing rust

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

\n\n

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

\n\n
    \n
  • 在没有连接设备的情况下进行测试(基本健全性检查,例如 CI 服务器)
  • \n
  • 测试共享功能(需要类型 1 或 2 的设备)
  • \n
  • 测试类型 2 专有功能(需要类型 2 的设备)
  • \n
\n\n

I\xe2\x80\x99m 使用功能来表示此行为:默认功能test-no-device和可选功能test-type-one以及test-type-two. 然后我使用该cfg_attr属性来忽略基于所选功能的测试:

\n\n
#[test]\n#[cfg_attr(not(feature = "test-type-two"), ignore)]\nfn test_exclusive() {\n    // ...\n}\n\n#[test]\n#[cfg_attr(not(any(feature = "test-type-two", feature = "test-type-one")), ignore)]\nfn test_shared() {\n    // ...\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n

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

\n\n

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

\n

She*_*ter 8

有没有一种简单的方法可以有条件地启用或忽略 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() {}
    }
}
Run Code Online (Sandbox Code Playgroud)

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

  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)
});
Run Code Online (Sandbox Code Playgroud)

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

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

[features]
test1 = []
test2 = ["test1"]
Run Code Online (Sandbox Code Playgroud)

如果您这样做,则不需要在配置属性中包含any或。all

默认功能test-no-device

这似乎没什么用;相反,使用由正常测试配置保护的正常测试:

#[cfg(test)]
mod test {
    #[test]
    fn no_device_needed() {}
}
Run Code Online (Sandbox Code Playgroud)

如果您遵循此操作,则可以从宏中删除这种情况。


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