Parameterized Rust Tests & Test Decorators

Build Status License: MIT OR Apache-2.0 rust 1.65+ required

Documentation: crate docs (main)

test-casing is a minimalistic Rust framework for generating tests for a given set of test cases and decorating them to add retries, timeouts, sequential test processing etc. In other words, the framework implements:

Since a separate test wrapper is generated for each case, their number should be reasonably low (roughly speaking, no more than 20). Isolating each test case makes most sense if the cases involve some heavy lifting (spinning up a runtime, logging considerable amount of information, etc.).

Usage

Add this to your Crate.toml:

toml [dev-dependencies] test-casing = "0.1.0"

Examples: test cases

```rust use testcasing::{cases, testcasing, TestCases}; use std::error::Error;

[test_casing(4, [2, 3, 5, 8])]

fn numeric_test(number: i32) { assert!(number < 10); }

// Cases can be extracted to a constant for better readability. const CASES: TestCases<(String, i32)> = cases! { [2, 3, 5, 8].map(|i| (i.to_string(), i)) };

[test_casing(4, CASES)]

fn parsingnumber( #[map(ref)] s: &str, // ^ specifies that argument should be borrowed from String // returned by the CASES iterator expected: i32, ) -> Result<(), Box> { asserteq!(s.parse::()?, expected); Ok(()) } ```

Other features include the support of async tests and ignore / should_panic attributes (the latter are applied to all generated cases).

```rust use testcasing::testcasing;

[test_casing(4, [2, 3, 5, 8])]

[async_std::test]

// ^ test attribute should be specified below the case spec async fn test_async(number: i32) { assert!(number < 10); }

[test_casing(3, ["not", "a", "number"])]

[should_panic(expected = "ParseIntError")]

fn parsingnumbererrors(s: &str) { s.parse::().unwrap(); } ```

Examples: test decorators

```rust use testcasing::{ decorate, testcasing, decorators::{Retry, Sequence, Timeout}, };

[test]

[decorate(Retry::times(3), Timeout::secs(3))]

fn testwithretryandtimeouts() { // Test logic }

static SEQUENCE: Sequence = Sequence::new().abortonfailure();

// Execute all test cases sequentially and abort if one of them fails.

[test_casing(4, [2, 3, 5, 8])]

[async_std::test]

[decorate(&SEQUENCE)]

async fn test_async(number: i32) { assert!(number < 10); } ```

See the crate docs for more examples of usage.

Descriptive test case names

With the help of [custom test frameworks] APIs and a generous spicing of hacks, the names of generated tests include the values of arguments provided to the targeted test function if the nightly crate feature is enabled. As the name implies, the feature only works on the nightly Rust.

Here's an excerpt of the output of integration tests in this crate to illustrate:

text test cartesian_product::case_6 [number = 5, s = "first"] ... ok test cartesian_product::case_9 [number = 8, s = "first"] ... ok test number_can_be_converted_to_string::case_0 [number = 2, expected = "2"] ... ok test number_can_be_converted_to_string::case_1 [number = 3, expected = "3"] ... ok test number_can_be_converted_to_string::case_2 [number = 5, expected = "5"] ... ok test number_can_be_converted_to_string_with_tuple_input::case_0 [(arg 0) = (2, "2")] ... ok test number_can_be_converted_to_string_with_tuple_input::case_1 [(arg 0) = (3, "3")] ... ok test number_can_be_converted_to_string_with_tuple_input::case_2 [(arg 0) = (5, "5")] ... ok test numbers_are_large::case_0 [number = 2] ... ignored, testing that `#[ignore]` attr works test numbers_are_large::case_1 [number = 3] ... ignored, testing that `#[ignore]` attr works test string_conversion_fail::case_0 [bogus_str = "not a number"] - should panic ... ok test string_conversion_fail::case_1 [bogus_str = "-"] - should panic ... ok test string_conversion_fail::case_2 [bogus_str = ""] - should panic ... ok test unit_test_detection_works ... ok

The arguments are a full-fledged part of test names, meaning that they can be included into test filters (like cargo test 'number = 3') etc.

Alternatives and similar tools

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 test-casing by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.