#parameterized #junit #unit-testing #parametrized #test-cases

sif

Small but convenient parameterized testing attribute macro for Rust

1 unstable release

0.1.0 Jul 7, 2020

#717 in Testing

MIT/Apache

10KB
72 lines

Sif

Sif provides a procedural macro which allows you to define a test to be run with multiple arguments. Test cases are defined using the 'parameterized' attribute instead of the 'test' attribute. This crate was inspired by the JUnit @ParameterizedTest annotation and builds on the development experience of the parameterized crate.

Examples:

Aside from the two examples below you can find additional examples in the sif_demo crate in this repository and in the tests folder.


Example: NPCs

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

enum NPC {
    Andre,
    Lautrec,
    Siegmeyer,
    Solaire,
}

trait Home {
    fn reigns_from(&self) -> &str;
}

impl Home for NPC {
    fn reigns_from(&self) -> &str {
        match self {
            NPC::Solaire | NPC::Andre => "Astora",
            NPC::Lautrec => "Carim",
            NPC::Siegmeyer => "Catarina",
        }
    }
}

#[parameterized]
#[case(NPC::Andre, "Astora")]
#[case(NPC::Lautrec, "Carim")]
#[case(NPC::Siegmeyer, "Catarina")]
#[case(NPC::Solaire, "Astrora")]
fn npc_reigns_from_test(npc: NPC, place: &str) {
    assert_eq!(npc.reigns_from(), place)
}


Importing Sif

With Rust 2018, there are two primary ways to import an attribute macro.

The first is by importing the macro into the local scope like a regular import, for example: use sif::parameterized;. This method also makes it easy to alias the macro's attribute to some other identifier, e.g. use sif::parameterized as pm;.

The second is by using extern crate in combination with the macro_use attribute (for example: #[cfg(test)] #[macro_use] extern crate sif;). This second option has an advantage if you use the macro a lot in your crate, since you only have to import it once at the root of the crate.

Running tests with IDE's

IntelliJ IDEA (+ intellij-rust)

IntelliJ IDEA recognises test cases and provides context menus which allow you to run tests within a certain scope (such as a module or a single test case), for example by clicking the ▶ icon in the gutter next to the start of a block containing a #[test]. Unfortunately, as attribute macros are currently not expanded, the IDE will not recognise the test cases generated by the sif::parameterized macro. Since I find this way of running tests rather useful, I opted to implement a simple workaround by providing a small declarative macro which expands to an empty test case. I've also attempted various other solutions, which will be documented in #ISSUENR.

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

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

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

/**/mod squared_tests { // <--
        use super::*;

        // this macro generates an empty test case which will mark the module as containing tests.
        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);
        }
    }
}

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.


Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~1.5MB
~33K SLoC