Writing async closure for testing

Hello, I'm trying to make this function accept an async test. I found this run test function here

Codebase is here

Ideally I would also be able to pass the server to the test function which I've been able to accomplish although it complains about thread problems.

The actual test closure still needs to be async.

pub async fn run_test<T>(test: T) -> ()
where
    T: FnOnce() -> () + panic::UnwindSafe,
{
    setup().await;
    // let srv = super::server().await;

    let text = "text";
    let result = panic::catch_unwind(|| test());

    teardown().await;

    assert!(result.is_ok())
}

This is the test which always complains of return opaque type and then If I switch T: FnOnce() -> () + panic::UnwindSafe,. To any sort of future it complains about not knowing the size.


#[actix_rt::test]
async fn test_index_get() {
    run_test(|| {
        {
           let srv = super::server().await;
            // let req = TestRequest::with_header("content-type", "text/plain").to_request();
            // let res = read_response(&mut srv, req).await;
            // assert_eq!(res, "Hello World".as_bytes());
            assert!(true);
        }
    })
    .await;
}

Any help would be greatly appreciated.

Thanks,

You define async closures as a generic parameter like this:

pub async fn run_test<T, Fut>(test: T) -> ()
where
    T: panic::UnwindSafe,
    T: FnOnce() -> Fut,
    Fut: Future<Output = ()>,
{
    ...
}

Trying to use Future as the return type directly doesn't work because Future is a trait, so if you try to use it as a type, you actually get the trait object type dyn Future, which is not the same as the trait, and is a specific concrete type that any future can be turned into. Since any future can be turned into a trait object dyn Future, it has no known size and must be boxed. To use the trait object, you would write it like this:

pub async fn run_test<T>(test: T) -> ()
where
    T: panic::UnwindSafe,
    T: FnOnce() -> Pin<Box<dyn Future<Output = ()>>>,
{
    ...
}

but I recommend using generics, as the above doesn't work with an async function directly. An async function returns a specific concrete type that implements future, which is different from the trait object type, so you must explicitly add a Box::pin(your_future) at the end to return the right type.

Regarding the catching of unwind thing, you can't use the standard catch unwind on a future, and you need this extension method to handle it.

1 Like

@Alice Thank you, while I'm working on trying the example above to better understand everything.

Kinda makes me thing just calling setup and tear down ends up being less boilerplate than I save.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.