test-case

repository·master·Indexed 20 days ago

https://github.com/frondeus/test-case

A Rust crate providing procedural macro attributes for generating parameterized test cases. It includes #[test_case(...)] for defining specific input/output scenarios and #[test_matrix(...)] for generating tests based on the Cartesian product of provided arguments, including lists, tuples, and numeric ranges. Version 3.3.1 supports the latest stable Rust version.

Tokens
1.5K
Snippets
6
Records
9
Agent score
67%

What's inside test-case

  1. MSRV Policy and version locking

    master
    As of version 3.0, test-case only supports the latest stable Rust version. If your environment uses an older Rust version, you should lock the dependency version in your Cargo.toml using the = operator to prevent breaking changes when new versions are released.
  2. Install and set up test-case

    master

    To use test-case in your project, add it to your dev-dependencies in Cargo.toml. Because the attribute name test_case collides with Rust's built-in custom_test_frameworks, you must explicitly import it into the scope of your test module using use test_case::test_case;.

    [dev-dependencies]
    test-case = "*"
    #[cfg(test)]
    mod tests {
        use test_case::test_case;
    
        // Your tests go here
    }
  3. MSRV Policy for test-case

    master

    Starting with version 3.0, test-case follows a policy of only supporting the latest stable Rust version. Because Rust updates can change compiler behavior overnight, if your project uses an older Rust version, you should lock test-case to a specific version in your Cargo.toml using the = operator to avoid breaking changes.

    Example:

    [dev-dependencies]
    test-case = "=3.3.1"
  4. Combine multiple test_case and test_matrix attributes

    master

    You can stack multiple #[test_case] or #[test_matrix] attributes on a single function. The macro will expand them all into individual tests within a generated mod named after your function.

    Supported attribute names for additional cases include:

    • test_case
    • test_case::test_case
    • test_case::case
    • case
    • test_matrix
    • test_case::test_matrix

    Note: When stacking, the macro processes these attributes and removes them from the original function to prevent interference, while preserving #[allow(...)] attributes.

  5. Install and setup test-case

    master

    To use test-case, add it to your dev-dependencies in Cargo.toml. Because the attribute name test_case collides with Rust's built-in custom_test_frameworks, you must explicitly import the macro into the scope where it is used.

    1. Add to Cargo.toml:
    [dev-dependencies]
    test-case = "*"
    1. Import in your test module:
    use test_case::test_case;
  6. Use the #[test_matrix] macro for Cartesian product testing

    master

    The #[test_matrix(...)] macro generates test cases by calculating the Cartesian product of the provided arguments. The number of arguments passed to the macro must match the number of arguments in the test function.

    Supported macro arguments:

    1. Lists/Tuples: Arrays [x, y, ...] or tuples (x, y, ...) containing valid expressions.
    2. Numeric Ranges: Closed ranges like 0..100 or 1..=99 to generate all integers in that range.
    3. Single Expressions: A single value used to keep an argument constant while others vary.
    #[cfg(test)]
    mod tests {
        use test_case::test_matrix;
    
        #[test_matrix(
            [-2, 2],
            [-4, 4]
        )]
        fn multiplication_tests(x: i8, y: i8) {
            let actual = (x * y).abs();
            assert_eq!(8, actual)
        }
    }
  7. Use the #[test_case] macro for parameterized tests

    master

    The #[test_case] procedural macro allows you to generate multiple test instances for a single function. Each attribute provides the arguments for the test function and an optional descriptive string. The string is used to name the generated test in the cargo test output.

    #[cfg(test)]
    mod tests {
        use test_case::test_case;
    
        #[test_case(-2, -4 ; "when both operands are negative")]
        #[test_case(2,  4  ; "when both operands are positive")]
        #[test_case(4,  2  ; "when operands are swapped")]
        fn multiplication_tests(x: i8, y: i8) {
            let actual = (x * y).abs();
            assert_eq!(8, actual)
        }
    }
  8. Use the #[test_matrix] attribute for Cartesian product testing

    master

    The #[test_matrix] attribute generates a test for every possible combination (the Cartesian product) of the provided sets of values.

    A test matrix consists of:

    1. Sets of values (Required): Multiple sets of values to combine. The number of sets must match the number of arguments in the test body.
    2. Expected result (Optional): An expected value applied to every combination generated.
    3. Test case description (Optional): A prefix applied to the generated test names.
    4. Test body (Required): The logic applied to every combination.

    This is useful for testing how a function behaves across a wide range of input permutations.

    #[test_matrix(vec![1, 2], vec!["a", "b"], "desc")]
    fn my_matrix_test(val: i32, s: &str) {
        // This will run for (1, "a"), (1, "b"), (2, "a"), and (2, "b")
    }
  9. Use the #[test_case] attribute for parameterized testing

    master

    The #[test_case] attribute allows you to run a single test function multiple times with different inputs.

    A test case consists of four elements:

    1. Arguments (Required): The values passed to the test body.
    2. Expected result (Optional): If provided, the macro uses assert_eq! to compare this value against the result of the test body.
    3. Test case description (Optional): A description used to identify the specific case.
    4. Test body (Required): The actual logic of the test.

    If you do not provide an expected result, your test body must contain custom assertions or return a Result (similar to a standard #[test]).

    #[test_case(1, 2, 3)] // Arguments: 1, 2; Expected: 3
    fn my_test(a: i32, b: i32, expected: i32) {
        assert_eq!(a + b, expected);
    }