#junit #test-cases #parametrized #test-macro #unit-testing #proc-macro

dev parameterized

过程宏,为 Rust 带来了紧凑的参数化测试实现(受JUnit @ParameterizedTest 启发)

9 个版本 (4 个稳定版)

2.0.0 2024年3月5日
1.1.0 2023年10月12日
1.0.1 2022年11月9日
1.0.0 2022年5月2日
0.1.0 2019年11月9日

#41 in 测试

Download history 1186/week @ 2024-04-20 1266/week @ 2024-04-27 1779/week @ 2024-05-04 1036/week @ 2024-05-11 1133/week @ 2024-05-18 771/week @ 2024-05-25 1230/week @ 2024-06-01 1046/week @ 2024-06-08 827/week @ 2024-06-15 1094/week @ 2024-06-22 2210/week @ 2024-06-29 1061/week @ 2024-07-06 1331/week @ 2024-07-13 1475/week @ 2024-07-20 1049/week @ 2024-07-27 932/week @ 2024-08-03

4,947 每月下载量
26 个crate中使用(23 个直接使用)

MIT/Apache

17KB
106

parameterized

基于过程宏的参数化测试库。当您想要运行具有许多不同输入集的测试用例时非常有用。

定义参数化测试用例时,应使用 #[parameterized(...)] 属性,而不是 #[test] 属性。

这个crate受到了JUnit @ParameterizedTest 的启发。

如果您考虑使用参数化,也可以查看 Yare,它是对 parameterized 的一种变体,它改变了参数的顺序,因此您可以定义自己的案例标识符。或者,还有 Sif,其中每个案例都可以由一个单独的 #[case(...)] 属性定义。

示例

更多示例可以在 parameterized-examples 仓库 中找到,以及在 测试 文件夹中。

enum Fruit {
    Apple,
    Bramble(BrambleFruit),
    Pear,
}

trait NameOf {
    fn name_of(&self) -> &str;
}

impl NameOf for Fruit {
    fn name_of(&self) -> &str {
        match self {
            Fruit::Apple => "apple",
            Fruit::Bramble(fruit) => fruit.name_of(),
            Fruit::Pear => "pear",
        }
    }
}

enum BrambleFruit {
    Blackberry,
}

impl NameOf for BrambleFruit {
    fn name_of(&self) -> &str {
        match self {
            BrambleFruit::Blackberry => "blackberry",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use parameterized::parameterized;


    #[parameterized(fruit = {
        Fruit::Apple, Fruit::Pear, Fruit::Bramble(BrambleFruit::Blackberry)
    }, name = {
        "apple", "pear", "blackberry"
    })]
    fn a_fruity_test(fruit: Fruit, name: &str) {
        assert_eq!(fruit.name_of(), name)
    }
}

自定义测试属性(例如 tokio::test)

默认情况下,parameterized 属性的代码生成步骤将生成带有 #[test] 属性的测试用例。例如,对于下面的参数化测试用例 add5,以下代码将被生成

参数化测试用例

use parameterized::parameterized;

#[parameterized(input = {
    0, 1
}, expected = {
    5, 6
})]
fn add5(input: u32, expected: u32) {
    assert_eq!(input + 5, expected);
}

生成的代码

#[cfg(test)]
mod add5 {
    use super::*;

    #[test]
    fn case_0() {
        assert_eq!(0 + 5, 5);
    }

    #[test]
    fn case_1() {
        assert_eq!(1 + 5, 6);
    }
}

然而,有时我们可能需要不同的测试宏,例如使用#[tokio::test]。为了让#[parameterized]使用用户指定的测试宏,您可以在#[parameterized]属性之后添加#[parameterized_macro(...)]属性。由于在这个例子中我们使用了#[tokio::test],因此我们也在函数签名中添加了async项(但当然,对于其他宏来说,这并非强制性的)。

使用#[parameterized_macro(...)]参数化的测试用例

#[parameterized(input = {
    0, 1
}, expected = {
    5, 6
})]
#[parameterized_macro(tokio::test)]
async fn add5(input: u32, expected: u32) {
    assert_eq!(input + 5, expected);
}

注意事项

  • #[parameterized_macro(...)]必须在#[parameterized]属性之后指定
  • 目前,每个参数化测试函数只支持一个#[parameterized_macro(...)]属性
  • 虽然您可以通过导入重命名来重命名参数化属性(例如,使用use parameterized::parameterized as pm),但parameterized_macro属性不能重命名,因为它实际上没有被定义为单独的宏。相反,parameterized将这个属性也解析为参数化的一部分。

导入

如果您不想在每一个测试模块中导入这个库(使用use parameterized::parameterized;),您可以将以下代码片段放在crate根目录的顶部

#[cfg(test)]
#[macro_use]
extern crate parameterized;

IDE '运行测试'意图

IntelliJ IDEA能够识别测试用例,并提供上下文菜单,允许您在特定的范围内运行测试(例如,模块或单个测试用例)。例如,在IntelliJ中,通常可以通过点击边栏中的▶图标来运行单个测试用例。遗憾的是,当前intellij-rust不支持展开属性宏。这意味着IDE将无法识别由属性宏生成的测试用例(例如,由本crate发布的parameterized宏生成的测试用例)。

以下是一个解决方案(如果您有更好的解决方案,请随时提出问题;提前感谢!)

fn squared(input: i8) -> i8 {
    input * input
}

#[cfg(test)]
mod tests {
    use super::*;

    use parameterized::parameterized as pm;
    use parameterized::ide;
        
    mod squared_tests { // <--
        use super::*;

        ide!(); // <--
    
        #[pm(input = {
            -2, -1, 0, 1, 2
        }, expected = {
            4, 1, 0, 1, 4
        })]
        fn test_squared(input: i8, output: i8) {
            assert_eq(squared(input), output);
        }
    }
}

在这里,我们创建了一个空的测试用例(使用 ide!() 宏),这将标记周围的模块为'包含测试用例'。在侧边栏中,您将在模块旁边找到 ▶ 图标。这允许您按模块运行测试用例。

注意:intellij-rust 可以扩展声明式宏(使用新宏引擎,可以在'设置'菜单中选择),例如这个 ide! 宏。


许可证

根据您的选择,许可协议为Apache License, Version 2.0MIT许可证

除非您明确表示,否则根据Apache-2.0许可证定义的,您有意提交以包含在此crate中的任何贡献,均应如上所述双重许可,无需任何额外条款或条件。

依赖项

~1.2–1.7MB
~33K SLoC