asomers / mockall

A powerful mock object library for Rust
Apache License 2.0
1.45k stars 61 forks source link

Can't `send` a Mock Object that returns Future #594

Closed JanzenJohn closed 1 month ago

JanzenJohn commented 1 month ago

I'm trying to mock a struct with several "Subscribers" which all have an async next() method.

But i only want to fire some in a given text, the others should return a futures::future::pending(). The solution i saw around for returning futures was to exchange the async await syntax for impl Future syntax so my mock! looks like this

mock! {
    #[derive(Debug)]
    pub Subscriber {
        pub fn next(&self) -> impl Future<Output=Option<Message>>;
    }
}

the expectation is built like this

let mut mock_subscriber = MockSubscriber::new();
mock_subscriber
  .expect_next()
  .returning(|| Box::pin(futures::future::pending()));

But if i try to move this struct into another thread i get a compiler error

error[E0277]: `dyn futures::Future<Output = std::option::Option<Message>>` cannot be sent between threads safely
   --> 
    |
    |         tokio::spawn(async move { created.run().await });
    |         ^^^^^^^^^^^^ `dyn futures::Future<Output = std::option::Option<Message>>` cannot be sent between threads safely
    |
    = help: the trait `std::marker::Send` is not implemented for `dyn futures::Future<Output = std::option::Option<Message>>`
    = note: required for `Unique<dyn futures::Future<Output = std::option::Option<Message>>>` to implement `std::marker::Send`

Do i need to implement the returning of futures differently? Or is there another way to make a mocked async function return a pending future?

asomers commented 1 month ago

You've defined your function as returning something that isn't Send. Try this instead:

mock! {
    #[derive(Debug)]
    pub Subscriber {
        pub fn next(&self) -> impl Future<Output=Option<Message>> + Send;
    }
}
JanzenJohn commented 1 month ago

that works, i didn't expect that the return of the function could impact if the Mock itself is send