How to run setup code before any tests run in Rust?
There's nothing built-in that would do this but this should help (you will need to call initialize()
in the beginning of every test):
use std::sync::Once;
static INIT: Once = Once::new();
pub fn initialize() {
INIT.call_once(|| {
// initialization code here
});
}
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.
If you use the ctor crate, you can take advantage of a global constructor function that will run before any of your tests are run.
Here's an example initialising the popular env_logger crate (assuming you have added ctor
to your [dev-dependencies]
section in your Cargo.toml
file):
#[cfg(test)]
#[ctor::ctor]
fn init() {
env_logger::init();
}
The function name is unimportant and you may name it anything.