Organized, flexible testing framework for Rust
Rust
Latest commit c1075d4 Nov 25, 2016 @ujh ujh Release 0.1.10

README.md

Stainless Build Status

Stainless is a lightweight, flexible, unopinionated testing framework.

Note that stainless currently requires the nightly version of the Rust compiler!

Installation

Add stainless as a dependency in your Cargo.toml file

[dev-dependencies]
stainless = "*"

Add the following lines to the top of your root module. That file is normally called src/main.rs for executables and src/lib.rs for libraries:

#![feature(plugin)]
#![cfg_attr(test, plugin(stainless))]

This will make stainless available when you run the tests using cargo test. When using stainless only with a library, make sure to run tests using cargo test --lib.

Overview

Stainless exports the describe! syntax extension, which allows you to quickly generate complex testing hierarchies and reduce boilerplate through before_each and after_each.

Stainless currently supports the following types of subblocks:

  • before_each and after_each
  • it, failing, and ignore
  • bench
  • nested describe!

before_each and after_each allow you to group common initialization and teardown for a group of tests into a single block, shortening your tests.

it generates tests which use before_each and after_each. failing does the same, except the generated tests are marked with #[should_panic]. It optionally takes an argument which is matched against the failure message. ignore is equivalent to marking a test with #[ignore] which disables the test by default.

bench allows you to generate benchmarks in the same fashion, though before_each and after_each blocks do not currently affect bench blocks.

Nested describe! blocks allow you to better organize your tests into small units and gives you granular control over where before_each and after_each apply. Of course the before_each and after_each blocks of the wrapping describe! blocks are executed as well.

Together, these 4 types of subblocks give you more flexibility and control than the built in testing infrastructure.

Example

describe! stainless {
    before_each {
        // Start up a test.
        let mut stainless = true;
    }

    it "makes organizing tests easy" {
        // Do the test.
        assert!(stainless);
    }

    after_each {
        // End the test.
        stainless = false;
    }

    bench "something simple" (bencher) {
        bencher.iter(|| 2 * 2)
    }

    describe! nesting {

        before_each {
          let mut inner_stainless = true;
        }

        after_each {
          inner_stainless = false;
        }

        it "makes it simple to categorize tests" {
            // It even generates submodules!
            assert_eq!(2, 2);
        }
    }
}

Expands to (roughly):

mod stainless {
    #[test]
    fn makes_organizing_tests_easy() {
        let mut stainless = true;
        assert!(stainless);
        stainless = false;
    }

    #[bench]
    fn something_simple(bencher: &mut test::Bencher) {
        bencher.iter(|| 2 * 2)
    }

    mod nesting {
        #[test]
        fn makes_it_simple_to_categorize_tests() {
            let mut stainless = true;
            let mut inner_stainless = true;
            assert_eq!(2, 2);
            inner_stainless = false;
            stainless = false;
        }
    }
}

Importing modules

At this point it is not possible to put use statements inside the describe! blocks. To allow usage of data structures from other modules and crates each describe! block comes with a silent pub use super::*; in it. That way everything you pub use in the containing module is available in your tests.

#[cfg(test)]
mod tests {
    pub use std::collections::HashMap;

    describe! stainless {
        it "can use HashMap" {
            let map = HashMap::new();
        }
    }
}

License

MIT. See the LICENSE file for details.

Authors

See Cargo.toml for the full list of authors.