Use mockall instead of mockall_derive
mastermockall_derive crate is an internal component and should never be used directly. To use the mocking capabilities provided by this project, you should use the primary mockall crate instead.repository·master·Indexed 23 days ago
https://github.com/asomers/mockallA powerful mock object library for Rust (v0.15.0) that allows developers to create objects with the same interface as real objects but with manually controlled responses for unit testing. It provides the #[automock] attribute for automatic mock generation of traits and structs, a mock! macro for manual mock definition, and a comprehensive expectation API to control return values, call counts, and call order using Sequence. Supports async traits and generic methods via #[mockall::concretize]. Requires Rust 1.77.0 or higher.
mockall_derive crate is an internal component and should never be used directly. To use the mocking capabilities provided by this project, you should use the primary mockall crate instead.Since mockall is typically used only for unit testing, add it to your dev-dependencies in Cargo.toml.
[dev-dependencies]
mockall = "0.15.0"To ensure that multiple expectations are called in a specific order, use a Sequence object. Any expectation can be added to the same sequence using .in_sequence(&mut sequence).
use mockall::{automock, Sequence};
#[automock]
trait Foo {
fn foo(&self);
}
let mut seq = Sequence::new();
let mut mock1 = MockFoo::new();
let mut mock2 = MockFoo::new();
mock1.expect_foo()
.times(1)
.in_sequence(&mut seq)
.returning(|| ());
mock2.expect_foo()
.times(1)
.in_sequence(&mut seq)
.returning(|| ());
// mock1.foo() MUST be called before mock2.foo(), otherwise it panics.use mockall::{automock, Sequence};
#[automock]
trait Foo {
fn foo(&self);
}
let mut seq = Sequence::new();
let mut mock1 = MockFoo::new();
let mut mock2 = MockFoo::new();
mock1.expect_foo()
.times(1)
.in_sequence(&mut seq)
.returning(|| ());
mock2.expect_foo()
.times(1)
.in_sequence(&mut seq)
.returning(|| ());Use Sequence to ensure that mock calls occur in a specific, predefined order. Sequences are performed greedily: they will always try to match the earliest possible element in the sequence that is currently allowed to be called.
let mut seq = Sequence::new();..in_sequence(&mut seq)..times(1..)), the first expectation will consume all calls, and the second expectation will never be reached, causing a test failure.# use mockall::*;
#[automock]
trait Foo {
fn foo(&self);
fn bar(&self) -> u32;
}
let mut seq = Sequence::new();
let mut mock0 = MockFoo::new();
let mut mock1 = MockFoo::new();
mock0.expect_foo()
.times(1)
.returning(|| ())
.in_sequence(&mut seq);
mock1.expect_bar()
.times(1)
.returning(|| 42)
.in_sequence(&mut seq);
mock0.foo();
mock1.bar();The easiest way to use Mockall is the #[automock] attribute. It generates a mock struct with the same name as your trait, prepended with Mock. You can then instantiate it using Mock<TraitName>::new(), set expectations on its methods, and provide it to your code.
use mockall::automock;
use mockall::predicate;
#[automock]
trait MyTrait {
fn foo(&self, x: u32) -> u32;
}
fn call_with_four(x: &dyn MyTrait) -> u32 {
x.foo(4)
}
#[test]
fn test_foo() {
let mut mock = MockMyTrait::new();
mock.expect_foo()
.with(predicate::eq(4))
.times(1)
.returning(|x| x + 1);
assert_eq!(5, call_with_four(&mock));
}use mockall::automock;
use mockall::predicate;
#[automock]
trait MyTrait {
fn foo(&self, x: u32) -> u32;
}
fn call_with_four(x: &dyn MyTrait) -> u32 {
x.foo(4)
}
#[test]
fn test_foo() {
let mut mock = MockMyTrait::new();
mock.expect_foo()
.with(predicate::eq(4))
.times(1)
.returning(|x| x + 1);
assert_eq!(5, call_with_four(&mock));
}By default, Mockall requires generic arguments to be 'static. To allow non-'static generic parameters, decorate the method with #[mockall::concretize]. This tells Mockall to treat generic arguments as trait objects.
#[mockall::concretize]. Aliasing it will cause it to fail..withf or .withf_st, not .with.expect_foo::<i32> and expect_foo::<u64>.T, &T, &mut T, and &[T] as generic parameters.# use std::path::Path;
# use mockall::{automock, concretize};
#[automock]
trait Foo {
#[mockall::concretize]
fn foo<P: AsRef<Path>>(&self, p: P);
}
# fn main() {
let mut mock = MockFoo::new();
mock.expect_foo()
.withf(|p| p.as_ref() == Path::new("/tmp"))
.return_const(());
mock.foo(Path::new("/tmp"));
# }When #[automock] is insufficient (e.g., mocking foreign types, structs with multiple impl blocks, or choosing a custom mock name), use the mock! macro. You must essentially redefine the structure and its implementations without bodies.
{} block containing method signatures (without bodies).impl blocks for traits (without bodies).Rc<T> implementing AsRef<T>).mock!{} block (e.g., type Item=u32;).# use mockall_derive::mock;
trait Foo {
fn foo(&self, x: u32);
}
mock!{
pub MyStruct<T: Clone + 'static> {
fn bar(&self) -> u8;
}
impl<T: Clone + 'static> Foo for MyStruct<T> {
fn foo(&self, x: u32);
}
}The #[automock] attribute is the easiest way to use Mockall. It works on most traits and structs with a single impl block. It generates a mock struct named Mock<Name> (e.g., MockFoo for Foo). For every method in the original, the mock struct provides an expect_<method_name> method to set expectations.
mock_<module_name> containing the functions.#[automock] Configuration#[automock(target = TraitName)] if you are using trait_variant and want to mock a specific variant instead of the local trait.#[automock(type Item=u32;)].#[automock] cannot be used for:
impl blocks.# use mockall_derive::automock;
#[automock]
pub trait Foo {
fn foo(&self, key: i16);
}
let mock = MockFoo::new();Mockall supports async traits (including those using the async_trait or trait_variant crates).
Important Requirements:
#[automock] attribute must appear before the crate's async attribute.impl Future, you must use Box::pin in your expectations.use async_trait::async_trait;
use mockall::automock;
use futures::{Future, future};
#[automock]
#[async_trait]
pub trait Foo {
async fn foo(&self) -> u32;
}
// For methods returning impl Future:
#[automock]
impl Foo {
fn foo(&self) -> impl Future<Output=i32> {
// ...
# future::ready(42)
}
}
let mut mock = MockFoo::new();
mock.expect_foo()
.returning(|| Box::pin(future::ready(42)));use async_trait::async_trait;
use mockall::automock;
use futures::{Future, future};
#[automock]
#[async_trait]
pub trait Foo {
async fn foo(&self) -> u32;
}
// For methods returning impl Future:
#[automock]
impl Foo {
fn foo(&self) -> impl Future<Output=i32> {
// ...
# future::ready(42)
}
}
let mut mock = MockFoo::new();
mock.expect_foo()
.returning(|| Box::pin(future::ready(42)));The easiest way to create a mock for a trait is to use the #[cfg_attr(test, automock)] attribute. This ensures the mock implementation is only generated during testing. When applied to a trait named MyTrait, it generates a struct named MockMyTrait.
#[cfg(test)]
use mockall::{automock, mock, predicate::*};
#[cfg_attr(test, automock)]
trait MyTrait {
fn foo(&self, x: u32) -> u32;
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn mytest() {
let mut mock = MockMyTrait::new();
mock.expect_foo()
.with(eq(4))
.times(1)
.returning(|x| x + 1);
assert_eq!(5, mock.foo(4));
}
}Once a mock object is instantiated (e.g., MockMyTrait::new()), you can define its behavior using an expectation API:
.expect_<method_name>(): Starts an expectation for a specific method..with(...): Defines arguments that the method must be called with. Uses predicates like eq() from mockall::predicate..times(n): Specifies exactly how many times the method should be called..returning(|args| ...): Defines the closure that provides the return value for the method call.