Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use async function in something like returning #252

Closed
ChrisGreenaway opened this issue Feb 11, 2021 · 8 comments
Closed

Use async function in something like returning #252

ChrisGreenaway opened this issue Feb 11, 2021 · 8 comments
Labels
question Usage question

Comments

@ChrisGreenaway
Copy link

I can't see anything in the API that would allow me to execute some async function when handling a method invocation.

Perhaps something like:
returning_async(|o| o.do_something_async.await)

@asomers
Copy link
Owner

asomers commented Feb 11, 2021

Mockall has special handling for async fn. See https://docs.rs/mockall/0.9.0/mockall/#async-traits . Your expectation will return a value which will be converted to an immediately ready future.

Or do you want to return a future that isn't ready yet? An async method is just fancy syntactical sugar for a method that returns a future. So if you dispense with async fn syntax, you can declare a method that returns a future, and return a future (ready or not) from your expectation. See https://github.com/asomers/mockall/blob/master/mockall/tests/automock_impl_future.rs .

@asomers asomers added the question Usage question label Feb 11, 2021
@ChrisGreenaway
Copy link
Author

I'm aware of the async_trait crate and I've been using that with mockall for some time.

But when handling the invocation to a mocked async function, I want to be able to use a lambda. The API has a returning function that allows me to do that. But I want to await on futures in that lambda.

Is that clearer?

@asomers
Copy link
Owner

asomers commented Feb 11, 2021

Can you just do this?

.returning(move || async move {
    whatever().await
})

@ChrisGreenaway
Copy link
Author

I don't actually need the moves because the thing I want to await on is a function on one of the parameters, but either way, it doesn't work. It complains that it was expecting the return type of the async function - in this case () - but instead it found a future.

    |
518 |               .returning(move |tasks,task_id,_,_| async move {
    |  _________________________________________________^
519 | |                 tasks.set_task_succeeded(&task_id).await;
520 | |                 ()
521 | |             });
    | |_____________^ expected `()`, found opaque type
    |
    = note: expected unit type `()`
             found opaque type `impl futures::Future`

@asomers
Copy link
Owner

asomers commented Feb 11, 2021

That suggests that your original method is defined as an async fn. When mocking an async fn, the expectation must the ready type of the function. So you'll have to do something like this:

.returning(move |...| async move {
        something.await;
        ()
    }.now_or_never().unwrap()
)

But if you really want to return a future that isn't ready yet, then you can't use an async fn. Instead, you'll have to define your method as one returning a future, like this:

mock!{
    Foo {
        // async fn foo(...) -> u32;    // If the real method looks like this, then mock it like:
        fn foo(...) -> impl Future<Output=u32>;
    }
}

@ChrisGreenaway
Copy link
Author

Yes - it is an async function and I do want to return a future that isn't necessarily ready yet.

Is this something mockall will support at some point in the future - perhaps when async fn is a first class feature?

@asomers
Copy link
Owner

asomers commented Feb 11, 2021

Potentially. It's something I use too on my own project. For me, the "normal function that returns a Future" method works fine. But I would have to figure out a clean syntax for it, and of course do all the work.

@asomers
Copy link
Owner

asomers commented Feb 11, 2021

It sounds like I've answered your question. And as a feature request, your request is the same as #189 . So I'm closing this issue as a duplicate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Usage question
Projects
None yet
Development

No branches or pull requests

2 participants