Stainless is a lightweight, flexible, unopinionated testing framework.
Note that stainless currently requires the nightly version of the Rust compiler!
Users are advised to use speculate.rs instead which implements a similar idea.
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
.
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
andafter_each
it
,failing
, andignore
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.
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;
}
}
}
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();
}
}
}
MIT. See the LICENSE file for details.
See Cargo.toml for the full list of authors.