I have a struct with implementation that uses automock from mockall crate:
pub struct MyStruct {...}
#[cfg_attr(test, automock)]
impl MyStruct {
...
pub async fn my_struct_function() {...}
...
}
I need to test that my_struct_function
is called exactly once by another async method:
Update: I expressed the problem in a poor manner. If other_async_method
calls my_struct_function
it's fine, they both run in the same task. But in my case other_async_method
spawns a new task and my_struct_function
is called in this new task. This is why the main task of the test doesn't "see" the panic and succeeds.
#[tokio::test]
async fn my_test() {
...
let mut my_struct_mock = MockMyStruct::default();
my_struct_mock.
.expect_my_struct_function()
.times(1)
.returning(...);
let result: Result<...> = OtherStruct::init_method(..., my_struct_mock, ...)
.other_async_method() // updated: spawns a new task that calls MockMyStruct::my_struct_function
.await;
...
}
At the moment if I change the times(1)
method to some other value N the test is still succesfull, because the code panics in a tokio thread, and not the main test thread.
I can verify it by running the test with nocapture
option:
$ cargo test my_test -- --nocapture
thread '...tests::test_my_test' panicked at 'MockMyStruct::my_struct_function: Expectation(<anything>) called 1 time(s) which is fewer than expected N'
How can I make the test fail when there is a discrepancy between the expected and the actual number of times the function is called?
I am a novice to Rust and wasn't able to find a solution sound by searching online. But I expect that there is a solution at the library level (mockall of tokio test) and not a "hack".
I opened an issue in the mockall GitHub repository: https://github.com/asomers/mockall/issues/461
The owner asomers suggested to use the checkpoint method and it solved my problem:
you can use mockedObject.checkpoint() to verify that all of its expectations have been satisfied prior to dropping the object.
#[tokio::test]
async fn my_test() {
...
let mut my_struct_mock = MockMyStruct::default();
my_struct_mock.
.expect_my_struct_function()
.times(1)
.returning(...);
let result: Result<...> = OtherStruct::init_method(..., my_struct_mock, ...)
.other_async_method() // updated: spawns a new task that calls MockMyStruct::my_struct_function
.await;
my_struct_mock.checkpoint();
...
}