How can I create parameterized tests in Rust?

后端 未结 6 2066
生来不讨喜
生来不讨喜 2021-02-05 01:20

I want to write test cases that depend on parameters. My test case should be executed for each parameter and I want to see whether it succeeds or fails for each parameter.

6条回答
  •  北海茫月
    2021-02-05 01:47

    EDIT: This is now on crates.io as parameterized_test::create!{...} - Add parameterized_test = "0.1.0" to your Cargo.toml file.


    Building off Chris Morgan’s answer, here's a recursive macro to create parameterized tests (playground):

    macro_rules! parameterized_test {
        ($name:ident, $args:pat, $body:tt) => {
            with_dollar_sign! {
                ($d:tt) => {
                    macro_rules! $name {
                        ($d($d pname:ident: $d values:expr,)*) => {
                            mod $name {
                                use super::*;
                                $d(
                                    #[test]
                                    fn $d pname() {
                                        let $args = $d values;
                                        $body
                                    }
                                )*
                            }}}}}}}
    

    You can use it like so:

    parameterized_test!{ even, n, { assert_eq!(n % 2, 0); } }
    even! {
        one: 1,
        two: 2,
    }
    

    parameterized_test! defines a new macro (even!) that will create parameterized tests taking one argument (n) and invoking assert_eq!(n % 2, 0);.

    even! then works essentially like Chris' fib_tests!, though it groups the tests into a module so they can share a prefix (suggested here). This example results in two tests functions, even::one and even::two.

    This same syntax works for multiple parameters:

    parameterized_test!{equal, (actual, expected), {
        assert_eq!(actual, expected); 
    }}
    equal! {
        same: (1, 1),
        different: (2, 3),
    }
    

    The with_dollar_sign! macro used above to essentially escape the dollar-signs in the inner macro comes from @durka:

    macro_rules! with_dollar_sign {
        ($($body:tt)*) => {
            macro_rules! __with_dollar_sign { $($body)* }
            __with_dollar_sign!($);
        }
    }
    

    I've not written many Rust macros before, so feedback and suggestions are very welcome.

提交回复
热议问题