在Rust中有条件启用或忽略整个测试套件的简单方法吗?

时间:2018-05-28 11:56:43

标签: unit-testing rust

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

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

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

我正在使用功能来表示此行为:默认功能test-no-device和可选功能test-type-onetest-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禁用编译排除的测试,但由于测试应该总是编译,我想避免这种情况。

1 个答案:

答案 0 :(得分:2)

  

是否有一种简单的方法可以有条件地启用或忽略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. 现有语法是否过于冗长?的
  3. 这是宏的候选者。

    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() {}
    }
    

    如果您这样做,可以从宏中删除此案例。

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