What it is
Mockall generates mock implementations of Rust traits and structs, with expectations on arguments, call counts and return values.
Annotate a trait with #[automock] to get a MockX type. Set expectations with matchers and return values, and assert on the calls made.
Installation
cargo add --dev mockallGetting started
The smallest useful thing you can do with it, and what each part means.
rust
use mockall::{automock, predicate::*};
#[automock]
#[async_trait]
trait BookStore {
async fn find(&self, id: u32) -> Option<Book>;
async fn save(&self, book: &Book) -> Result<(), StoreError>;
}
#[tokio::test]
async fn returns_the_book() {
let mut store = MockBookStore::new();
store.expect_find()
.with(eq(42)) // only matches this argument
.times(1) // and exactly once
.returning(|_| Some(Book::default()));
let service = Service::new(store);
assert!(service.get(42).await.is_some());
// Expectations are verified when the mock is dropped.
}Advanced usage
Where the library earns its place over a simpler alternative.
rust
let mut seq = mockall::Sequence::new();
store.expect_find()
.times(1)
.in_sequence(&mut seq)
.returning(|_| None);
store.expect_save()
.times(1)
.in_sequence(&mut seq) // must happen after find
.returning(|_| Ok(()));
// Different responses on successive calls.
let mut count = 0;
store.expect_find().returning(move |_| {
count += 1;
if count < 3 { None } else { Some(Book::default()) }
});Errors and fixes
The failures you are most likely to hit, and what actually resolves them.
- No matching expectation found
- The call arguments do not match any `with` clause. Loosen the matcher or add the missing expectation — the panic message shows the actual arguments.
- automock does not work on a generic trait
- Use mock! to declare the mock manually; #[automock] has limits with generics and lifetimes.
Best practices
- Mock traits you own; mocking a third-party API couples your tests to someone else's design.
- Prefer a real database via a test container over mocking the data layer — mocks of complex systems drift from reality.
- Use precise matchers rather than `always`, or the test proves very little.
- Keep the trait small; a mock with fifteen methods is a design signal.
Background
Why it exists, and what it was reacting to.
Rust's static dispatch makes runtime mocking impossible in the style of dynamic languages. Mockall solves it with macros that generate a mock type at compile time.
