The problem is package A has a public async trait (using async_trait) with an async method. Package B - the axum router - consumes that trait which is injected as an extension.
How can a test double (mock, spy, stub) that implements that trait be built with some tool (like mockall or another)?
I tried to manually craft the test double, but I had to change the receiver in the trait from &self to &mut self to be able to track the state (calls, params etc) - which I do not like to do. But if it's the only option, I guess it has to do.
I don't know about using a mock crate to sugar over the trait implementation, but you can fix the state tracking thing in your hand-written impl with some good old fashioned interior mutability:
use tokio::sync::Mutex;
struct Mock {
state: Mutex<State>,
}
struct State(i32);
#[async_trait]
impl AsyncTrait for Mock {
async fn do_something(&self) {
let mut state = self.state.lock().await;
// Feel free to mutate `state` all you need!
state.0 = 42;
}
}
edit: The previous revision of the example code wrapped the mutex in Arc, but the shared ownership may not be necessary for this use case.