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.