使用同步代码时,我可以像这样使用
panic::catch_unwind
:
#[actix_rt::test]
async fn test_sync() -> Result<(), Error> {
println!("before catch_unwind");
let sync_result = panic::catch_unwind(|| {
println!("inside sync catch_unwind");
panic!("this is error")
});
println!("after catch_unwind");
assert!(sync_result.is_ok());
Ok(())
}
在使用
catch_unwind
块内执行的异步代码时,如何执行相同的操作?我不知道如何运行该块,同时也能够在该块之后运行一些代码并最终断言结果。
这是我到目前为止所拥有的:
#[actix_rt::test]
async fn test_async() -> Result<(), Error> {
println!("before catch_unwind");
let async_result = panic::catch_unwind(|| async {
println!("inside async catch_unwind");
panic!("this is error")
}).await;
println!("after catch_unwind");
assert!(async_result.is_ok());
Ok(())
}
FutureExt::catch_unwind
和 StreamExt::catch_unwind
。
use futures::FutureExt; // 0.3.5
#[tokio::test]
async fn test_async() -> Result<(), Box<dyn std::error::Error>> {
println!("before catch_unwind");
let may_panic = async {
println!("inside async catch_unwind");
panic!("this is error")
};
let async_result = may_panic.catch_unwind().await;
println!("after catch_unwind");
assert!(async_result.is_ok());
Ok(())
}
我遇到了这个问题,Shepmaster 的答案确实部分有效。我遇到了很多错误,其中包含有关展开和不安全传输变量的非常复杂的描述。在您对已接受答案的评论中,您也解决了这个问题。
下面的解决方法解决了我的问题。我不建议在测试之外使用它,因为这种方式可能很昂贵。它使用互斥体和当前运行时(句柄)。
fn main() {}
#[cfg(test)]
mod test {
#[tokio::test]
async fn test() {
env_logger::init();
// This variable represents your complex type
// Note that this can be a combination of types if you use a tuple or something else
let my_complex_type = 1;
// Wrap it all in a std::sync::Mutex
let mutex = std::sync::Mutex::new(my_complex_type);
// Pass the mutex in the panic unwind
assert!(std::panic::catch_unwind(|| {
// Now you can work with your complex type
let my_complex_type = mutex.lock().unwrap();
// Enter the runtime
let handle = tokio::runtime::Handle::current();
handle.enter();
futures::executor::block_on(do_something(*my_complex_type));
}).is_err());
}
async fn do_something(t: i32) {
panic!();
}
}
为了避免一百个左右的“可能无法安全地跨展开边界传输”错误的“乐趣”,您可以使用
AssertUnwindSafe
包装器类型 告诉编译器仅使用 STFU。官方文档中确实没有一个很好的async
友好示例,但以下是我如何获得需要运行后清理才能工作的异步测试:
#[actix_rt::test]
async fn password_auth() {
let b = Browser::new().await;
let result = AssertUnwindSafe(run_password_auth(b.clone())).catch_unwind().await;
b.close().await;
if let Err(e) = result {
panic!("{:?}", e);
}
}
async fn run_password_auth(b: Browser) {
// .await away!
}