Just to give people more ideas (for example, how not to call setup
in every test), one additional thing you could do is to write a helper like this:
fn run_test<T>(test: T) -> ()
where T: FnOnce() -> () + panic::UnwindSafe
{
setup();
let result = panic::catch_unwind(|| {
test()
});
teardown();
assert!(result.is_ok())
}
Then, in your own tests you would use it like this:
#[test]
fn test() {
run_test(|| {
let ret_value = function_under_test();
assert!(ret_value);
})
}
You can read more about UnwindSafe
trait and catch_unwind
here: https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
I've found the original idea of this test helper in this medium article by Eric Opines.
Also, there is rstest crate which has pytest-like fixtures which you can use as a setup code (combined with the Jussi Kukkonen's answer:
use std::sync::Once;
use rstest::rstest;
static INIT: Once = Once::new();
pub fn setup() -> () {
INIT.call_once(|| {
// initialization code here
});
}
#[rstest]
fn should_success(setup: ()) {
// do your test
}
Maybe one day rstest will gain scopes support and Once
won't be needed anymore.
#[warn(dead_code)]
on by default". Please help me to fix it. Thanks! – Anasarca