Test setup and teardown in Rust without a framework.
When I read the announcement about being able to handle panics using catch_unwind (https://doc.rust-lang.org/std/panic/fn.catch_unwind.html) I thought I would never have a reason to use it. But…
I’m testing some code that requires a fair amount of setup and teardown and I wanted to DRY it up. The problem was that the teardown step in the original code had to run before the test assertion otherwise the teardown code wouldn’t run if a test failed. asserts panic and nothing after the assert will run.
The original code looked something like:
#[test]
fn test_something_interesting() {
setup();
let true_or_false = do_the_test();
teardown();
assert!(true_or_false);
}
The refactored code looked like:
#[test]
fn test_something_interesting() {
run_test(|| {
let true_or_false = do_the_test();
assert!(true_or_false);
})
}
fn run_test<T>(test: T) -> ()
where T: FnOnce() -> ()
{
setup();
test();
teardown();
}
which doesn’t work because if the assert fails teardown() will never run.
Then I started to write a macro which I won’t even post here because your eyes will bleed and I never got it to work and I hated it and I dislike macros in general.
After a little googling and realizing I needed a way to catch a panic…
Oh, yah. The announcement.
A little experimentation and I wound up with:
#[test]
fn test_something_interesting() {
run_test(|| {
let true_or_false = do_the_test();
assert!(true_or_false);
})
}fn run_test<T>(test: T) -> ()
where T: FnOnce() -> () + panic::UnwindSafe
{
setup();
let result = panic::catch_unwind(|| {
test()
});
teardown();
assert!(result.is_ok())
}
The coolest thing about this solution is that it produces the same errors the assert panic would produce in the original code.
I tried to find code or a blog or some other documentation where this is being done. I didn’t find anything. So it’s either really bad or no one is talking about it for some reason. Please let me know if there’s something wrong with doing this.