TL;DR:
mockallgenerates mock implementations of Rust traits using the#[automock]attribute ormock!macro. Mock objects record calls, allow setting return values, and verify that expected calls were made. Use mocks to test code that depends on external systems (databases, HTTP clients, email senders) without hitting the real services.mockallworks with both sync and async traits (viaasync-trait).
What Is mockall?
mockall generates a MockTrait struct for any trait; the mock records method calls and lets you define expectations and return values in tests.
# Cargo.toml
[dev-dependencies]
mockall = "0.13"How Do You Create a Mock?
Add #[automock] to a trait; mockall generates a MockTraitName struct.
use mockall::automock;
#[automock]
trait UserRepository {
fn find_by_id(&self, id: u64) -> Option<User>;
fn save(&mut self, user: &User) -> Result<(), String>;
fn count(&self) -> usize;
}
#[derive(Clone, Debug, PartialEq)]
struct User {
id: u64,
name: String,
}#[automock] generates MockUserRepository with the same interface plus expectation-setting methods.
How Do You Set Expectations in Tests?
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::*;
#[test]
fn test_get_user_name() {
let mut mock = MockUserRepository::new();
// Expect find_by_id to be called once with id=42, return Some(user)
mock.expect_find_by_id()
.with(eq(42u64)) // argument matcher
.times(1) // must be called exactly once
.returning(|_| Some(User { id: 42, name: "Alice".to_string() }));
// Code under test uses the mock
let service = UserService::new(Box::new(mock));
let name = service.get_user_name(42);
assert_eq!(name, Some("Alice".to_string()));
// mockall verifies expectations when mock is dropped
}
#[test]
fn test_user_not_found() {
let mut mock = MockUserRepository::new();
mock.expect_find_by_id()
.returning(|_| None); // any call returns None
let service = UserService::new(Box::new(mock));
assert_eq!(service.get_user_name(999), None);
}
}How Do You Mock Async Traits?
Use #[automock] together with async-trait; the generated mock supports .await.
use async_trait::async_trait;
use mockall::automock;
#[automock]
#[async_trait]
trait EmailSender: Send + Sync {
async fn send(&self, to: &str, subject: &str, body: &str) -> Result<(), String>;
}
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_welcome_email_sent() {
let mut mock = MockEmailSender::new();
mock.expect_send()
.with(
mockall::predicate::eq("[email protected]"),
mockall::predicate::function(|s: &str| s.contains("Welcome")),
mockall::predicate::always(),
)
.times(1)
.returning(|_, _, _| Ok(()));
let service = OnboardingService::new(Arc::new(mock));
service.onboard_user("[email protected]").await.unwrap();
}
}What Argument Matchers Are Available?
use mockall::predicate::*;
// Exact value
.with(eq(42))
// Any value
.with(always())
// Custom predicate
.with(function(|x: &i32| *x > 0))
// String contains
.with(str::contains("hello"))
// Multiple args (use .withf for closures)
.withf(|a, b| a + b == 10)Frequently Asked Questions
Use mocks when: the real dependency is slow, has side effects, is hard to set up (real database, third-party API), or you want to test error paths that are hard to trigger with a real system. Use integration tests to verify the real interactions work; mocks and integration tests complement each other.
mockall works best with traits. For concrete structs, you can use mock! to manually define the mock, but it's more verbose. The best pattern is to always depend on traits, not concrete types; this makes mocking easy and follows dependency inversion.
Each expect_ method sets an expectation; how many times the method should be called, with what arguments, and what to return. When the mock is dropped (at the end of the test), mockall verifies all expectations were met. Unexpected calls cause a panic.
Yes; create a helper function that returns a configured mock, or use MockAll::checkpoint() to verify mid-test and reset expectations.
Sources
Related Glossary Terms
- Trait: Mockall generates mocks for traits
- async-trait: Required for mocking async trait methods
- Arc: Mocks are often wrapped in
Arcfor shared use
Keep Reading
- Rust Error Handling: Result and Option: testing error paths is where mocking earns its keep
- Learn Rust in 2026: testing is a first-class citizen in Rust

