代码之家  ›  专栏  ›  技术社区  ›  Robin Krahl

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

  •  2
  • Robin Krahl  · 技术社区  · 7 年前

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

    我想为不同的环境提供不同的测试套件:

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

    i_m使用功能来表示此行为:默认功能 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 在模块上,但是由于测试应该总是编译,所以我想避免这种情况。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Shepmaster Tim Diekmann    7 年前

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

    这个 最简单的 甚至不编译测试:

    #[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. 你能用纯锈来表示你想要的功能吗?
    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"]
    

    如果你这样做,你不需要 any all 在配置属性中。

    默认功能 test-no-device

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

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

    如果遵循此操作,则可以从宏中删除此案例。


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