10 releases (6 breaking)

0.6.1 Feb 24, 2024
0.6.0 Oct 2, 2022
0.5.0 Aug 28, 2022
0.4.0 Jul 16, 2022
0.0.2 Jul 5, 2022

#1662 in Procedural macros

Download history 11/week @ 2024-05-31 5/week @ 2024-06-07 2/week @ 2024-06-28 42/week @ 2024-07-05 56/week @ 2024-07-26 11/week @ 2024-08-02

147 downloads per month
Used in 2 crates

MIT/Apache

16KB
325 lines

beady

A macro for writing tests in a Behaviour Driven (BD) style. Inspired by Catch2.

  • Simple (doesn't really do anything except rearrange your tests)
  • Provides helpful output for when tests fail
  • Works with tokio::test (and other custom test attributes)

Example

use beady::scenario;

#[scenario]
#[test]
fn pushing_an_element_to_a_vec() {
    'given_an_empty_vec: {
        let mut vec = vec![];
        
        'when_an_element_is_pushed_to_the_vec: {
            vec.push(7);
            
            'then_the_vec_should_have_one_element: {
                assert_eq!(vec.len(), 1);
                
                'and_then_that_element_should_be_the_pushed_value: {
                    assert_eq!(vec[0], 7);
                }
            }
            
            'and_when_the_vec_is_cleared: {
                vec.clear();
                
                'then_the_vec_should_be_empty: {
                    assert!(vec.is_empty());
                }
            }
        }
    }
}

Running cargo test we can see that this scenario has generated three tests:

running 3 tests
test pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::then::the_vec_should_have_one_element::and::the_element_should_be_the_pushed_value ... ok
test pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::and::the_vec_is_cleared::then::the_vec_should_be_empty ... ok
test pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::then::the_vec_should_have_one_element ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in 0.00s

And if we make one of our asserts intentionally fail then we see a full description of the failing scenario alongside the panic message:

test pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::then::the_vec_should_have_one_element::and::the_element_should_be_the_pushed_value ... FAILED

failures:

---- pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::then::the_vec_should_have_one_element::and::the_element_should_be_the_pushed_value stdout ----

Scenario: pushing an element to a vec
   Given: an empty vec
    When: an element is pushed to the vec
    Then: the vec should have one element
     and: the element should be the pushed value

thread 'pushing_an_element_to_a_vec::given::an_empty_vec::when::an_element_is_pushed_to_the_vec::then::the_vec_should_have_one_element::and::the_element_should_be_the_pushed_value' panicked at 'assertion failed: `(left == right)`
  left: `7`,
 right: `8`'

Usage

Inspired by the BDD-style test cases from Catch2, you can annotate a test with #[scenario] to make it into a BDD-style test. Within the test you can then use 'given_, 'when_, and 'then_ prefixes to label blocks and structure your test cases. Dependent clauses can be specified with the 'and_given_, 'and_when_, and 'and_then_ prefixes.

Dependencies

~1.5MB
~36K SLoC