/section_testing

A Rust library for section-style testing

Primary LanguageRustMIT LicenseMIT

This is a small library that enables section-style testing in Rust. Section-style testing makes writing many similar test cases easy, natural, and concise.

Each top-level section test is run repeatedly, once for every unique section inside the test. This is more expressive and natural than fixtures because it lets you use local variables from parent scopes inside a section and because you can nest sections to an arbitrary depth.

Getting Started

This library is published at https://crates.io/crates/section_testing. Add the following dependency to your Cargo.toml:

[dependencies]
section_testing = "0.0.5"

Read the example below to learn how to use it.

Example

Here's an example:

#[macro_use]
extern crate section_testing;

enable_sections! {
  #[test]
  fn example_test() {
    let mut v: Vec<i32> = vec![];

    fn check_123(v: &mut Vec<i32>) {
      assert_eq!(*v, vec![1, 2, 3]);

      if section!("reverse") {
        v.reverse();
        assert_eq!(*v, vec![3, 2, 1]);
      }

      if section!("pop+remove+insert+push") {
        let three = v.pop().unwrap();
        let one = v.remove(0);
        v.insert(0, three);
        v.push(one);
        assert_eq!(*v, vec![3, 2, 1]);
      }
    }

    if section!("push") {
      v.push(1);
      v.push(2);
      v.push(3);
      check_123(&mut v);
    }

    if section!("insert") {
      v.insert(0, 3);
      v.insert(0, 1);
      v.insert(1, 2);
      check_123(&mut v);
    }
  }
}

The enable_sections! macro modifies the test functions inside of it so that they run repeatedly until all sections have been visited. The section! macro returns a bool for whether or not that section should be run this iteration. This example test will check the following combinations:

push
push, reverse
push, pop+remove+insert+push
insert
insert, reverse
insert, pop+remove+insert+push

When a test fails, the enclosing sections will be printed to stderr. Here's what happens if we comment out v.push(one); in the example above:

running 1 test
thread 'example_test' panicked at 'assertion failed: `(left == right)`
  left: `[3, 2]`,
 right: `[3, 2, 1]`', src/main.rs:30:9
note: Run with `RUST_BACKTRACE=1` for a backtrace.
---- the failure was inside these sections ----
  0) "push" at src/main.rs:34
  1) "pop+remove+insert+push" at src/main.rs:25
test example_test ... FAILED

Note that like all tests in Rust, a section-style test will stop on the first failure. This means you will only be able to see the first combination that failed instead of being able to see all failed combinations. The above example would have also failed for the combination insert, pop+remove+insert+push if the other combination hadn't failed first. This is because Rust's built-in test runner has no API for adding new tests at runtime.