[][src]Crate mockall

A powerful mock object library for Rust.

Mockall provides provides tools to create mock versions of almost any trait or struct. They can be used in unit tests as a stand-in for the real object.

Usage

There are three ways to use Mockall. The easiest is to use [#[automock]]. It can mock most traits, or structs that only have a single impl block. For things it can't handle, there is [mock!]. Finally, there are rare cases where one may need to manually construct a mock object using expectation!.

Whichever method is used, the basic idea is the same.

  • Create a mock struct. It's name will be the same as the original, with "Mock" prepended.
  • In your test, instantiate the mock struct with its new or default method.
  • Set expectations on the mock struct. Each expectation can have required argument matchers, a required call count, and a required position in a Sequence. Each expectation must also have a return value.
  • Supply the mock object to the code that you're testing. It will return the preprogrammed return values supplied in the previous step. Any accesses contrary to your expectations will cause a panic.

User Guide

Getting Started

use mockall::*;
use mockall::predicate::*;
#[automock]
trait MyTrait {
    fn foo(&self, x: u32) -> u32;
}

fn call_with_four(x: &MyTrait) -> u32 {
    x.foo(4)
}

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));

Return values

Every expectation must have an associated return value (though when the nightly feature is enabled expectations will automatically return the default values of their return types, if their return types implement Default.). For 'static return types there are two ways to set the return value: with a constant or a closure. A closure will take the method's arguments by value.

#[automock]
trait MyTrait {
    fn foo(&self) -> u32;
    fn bar(&self, x: u32, y: u32) -> u32;
}

let mut mock = MockMyTrait::new();
mock.expect_foo()
    .return_const(42u32);
mock.expect_bar()
    .returning(|x, y| x + y);

Additionally, constants that aren't Clone can be returned with the [return_once] method.

struct NonClone();
#[automock]
trait Foo {
    fn foo(&self) -> NonClone;
}

let mut mock = MockFoo::new();
let r = NonClone{};
mock.expect_foo()
    .return_once(move || r);

[return_once] can also be used for computing the return value with an FnOnce closure. This is useful for returning a non-Clone value and also triggering side effects at the same time.

fn do_something() {}

struct NonClone();

#[automock]
trait Foo {
    fn foo(&self) -> NonClone;
}

let mut mock = MockFoo::new();
let r = NonClone{};
mock.expect_foo()
    .return_once(move || {
        do_something();
        r
    });

Mock objects are always Send. If you need to use a return type that isn't, you can use the [returning_st] or [return_once_st] methods. These take a non-Send object and add runtime access checks. The wrapped object will be Send, but accessing it from multiple threads will cause a runtime panic.

#[automock]
trait Foo {
    fn foo(&self, x: Rc<u32>) -> Rc<u32>;   // Rc<u32> isn't Send
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .withf(|x| **x == 5)
    .returning_st(move |_| Rc::new(42u32));
assert_eq!(42, *mock.foo(Rc::new(5)));

Matching arguments

Optionally, expectations may have argument matchers set. A matcher will verify that the expectation was called with the expected arguments, or panic otherwise. A matcher is anything that implements the Predicate trait. For example:

#[automock]
trait Foo {
    fn foo(&self, x: u32);
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .with(eq(42))
    .return_const(());

mock.foo(0);    // Panics!

See predicates for a list of Mockall's builtin predicate functions. For convenience, [withf] is a shorthand for setting the commonly used [function] predicate. The arguments to the predicate function are the method's arguments, by reference. For example:

#[automock]
trait Foo {
    fn foo(&self, x: u32, y: u32);
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .withf(|x: &u32, y: &u32| x == y)
    .return_const(());

mock.foo(2 + 2, 5);    // Panics!

Matching multiple calls

Matchers can also be used to discriminate between different invocations of the same function. Used that way, they can provide different return values for different arguments. The way this works is that on a method call, all expectations set on a given method are evaluated in FIFO order. The first matching expectation is used. Only if none of the expectations match does Mockall panic. For example:

#[automock]
trait Foo {
    fn foo(&self, x: u32) -> u32;
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .with(eq(5))
    .return_const(50u32);
mock.expect_foo()
    .with(eq(6))
    .return_const(60u32);

One common pattern is to use multiple expectations in order of decreasing specificity. The last expectation can provide a default or fallback value, and earlier ones can be more specific. For example:

#[automock]
trait Foo {
    fn open(&self, path: String) -> Option<u32>;
}

let mut mock = MockFoo::new();
mock.expect_open()
    .with(eq(String::from("something.txt")))
    .returning(|_| Some(5));
mock.expect_open()
    .return_const(None);

Call counts

By default, every expectation is allowed to be called an unlimited number of times. But Mockall can optionally verify that an expectation was called a fixed number of times, or any number of times within a given range.

#[automock]
trait Foo {
    fn foo(&self, x: u32);
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .times(1)
    .return_const(());

mock.foo(0);    // Ok
mock.foo(1);    // Panics!

See also [never], [times], [times_any], and [times_range].

Sequences

By default expectations may be matched in any order. But it's possible to specify the order by using a Sequence. Any expectations may be added to the same sequence. They don't even need to come from the same object.

#[automock]
trait Foo {
    fn foo(&self);
}

let mut seq = Sequence::new();

let mut mock1 = MockFoo::new();
mock1.expect_foo()
    .in_sequence(&mut seq)
    .returning(|| ());

let mut mock2 = MockFoo::new();
mock2.expect_foo()
    .in_sequence(&mut seq)
    .returning(|| ());

mock2.foo();    // Panics!  mock1.foo should've been called first.

Checkpoints

Sometimes its useful to validate all expectations mid-test, throw them away, and add new ones. That's what checkpoints are for. Every mock object has a checkpoint method. When called, it will immediately validate all methods' expectations. So any expectations that haven't satisfied their call count will panic. Afterwards, those expectations will be cleared so you can add new expectations and keep testing.

#[automock]
trait Foo {
    fn foo(&self);
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .times(2)
    .returning(|| ());

mock.foo();
mock.checkpoint();  // Panics!  foo hasn't yet been called twice.
#[automock]
trait Foo {
    fn foo(&self);
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .times(1)
    .returning(|| ());

mock.foo();
mock.checkpoint();
mock.foo();         // Panics!  The expectation has been cleared.

Reference arguments

Mockall can mock methods with reference arguments, too. There's one catch: the matcher Predicate will take reference arguments by value, not by reference.

#[automock]
trait Foo {
    fn foo(&self, x: &u32) -> u32;
}

let mut mock = MockFoo::new();
let e = mock.expect_foo()
    // Note that x is a &u32, not a &&u32
    .withf(|x: &u32| *x == 5)
    .returning(|x: &u32| *x + 1);

assert_eq!(6, mock.foo(&5));

Reference return values

Mockall can also use reference return values. There is one restriction: the lifetime of the returned reference must be either the same as the lifetime of the mock object, or 'static.

Mockall creates different expectation types for methods that return references. Their API is the same as the usual [Expectation], except for setting return values.

Methods that return 'static references work just like methods that return any other 'static value.

struct Thing(u32);

#[automock]
trait Container {
    fn get(&self, i: u32) -> &'static Thing;
}

const THING: Thing = Thing(42);
let mut mock = MockContainer::new();
mock.expect_get()
    .return_const(&THING);

assert_eq!(42, mock.get(0).0);

Methods that take a &self argument use the [RefExpectation] class, which gets its return value from the return_const method.

struct Thing(u32);

#[automock]
trait Container {
    fn get(&self, i: u32) -> &Thing;
}

let thing = Thing(42);
let mut mock = MockContainer::new();
mock.expect_get()
    .return_const(thing);

assert_eq!(42, mock.get(0).0);

Methods that take a &mut self argument use the [RefMutExpectation] class, regardless of whether the return value is actually mutable. They can take their return value either from the return_var or returning methods.

struct Thing(u32);

#[automock]
trait Container {
    fn get_mut(&mut self, i: u32) -> &mut Thing;
}

let thing = Thing(42);
let mut mock = MockContainer::new();
mock.expect_get_mut()
    .return_var(thing);

mock.get_mut(0).0 = 43;
assert_eq!(43, mock.get_mut(0).0);

Unsized types that are common targets for [Deref] are special. Mockall will automatically use the type's owned form for the Expectation. Currently, the str, [CStr], [OsStr], and [Path] types are supported. Using this feature is automatic:

#[automock]
trait Foo {
    fn name(&self) -> &str;
}

let mut mock = MockFoo::new();
mock.expect_name().return_const("abcd".to_owned());
assert_eq!("abcd", mock.name());

Impl Trait

Rust 1.26.0 introduced the impl Trait feature. It allows functions to return concrete but unnamed types (and, less usefully, to take them as arguments). It's almost the same as Box<dyn Trait> but without the extra allocation. Mockall supports deriving mocks for methods that return impl Trait, with limitations. When you derive the mock for such a method, Mockall internally transforms the Expectation's return type to Box<dyn Trait>, without changing the mock method's signature. So you can use it like this:

struct Foo {}
#[automock]
impl Foo {
    fn foo(&self) -> impl Debug {
        // ...
    }
}

let mut mock = MockFoo::new();
mock.expect_foo()
    .returning(|| Box::new(String::from("Hello, World!")));
println!("{:?}", mock.foo());

However, impl Trait isn't exactly equivalent to Box<dyn Trait> but with fewer allocations. There are some things the former can do but the latter can't. For one thing, you can't build a trait object out of a Sized trait. So this won't work:

This example deliberately fails to compile
struct Foo {}
#[automock]
impl Foo {
    fn foo(&self) -> impl Clone {
        // ...
    }
}

Nor can you create a trait object that implements two or more non-auto types. So this won't work either:

This example deliberately fails to compile
struct Foo {}
#[automock]
impl Foo {
    fn foo(&self) -> impl Debug + Display {
        // ...
    }
}

For such cases, there is no magic bullet. The best way to mock methods like those would be to refactor them to return named (but possibly opaque) types instead.

See Also impl-trait-for-returning-complex-types-with-ease.html

Mocking structs

Mockall mock structs as well as traits. The problem here is a namespace problem: it's hard to supply the mock object to your code under test, because it has a different name. The solution is to alter import paths during test. The [cfg-if] crate helps.

[#[automock]] works for structs that have a single impl block:

mod thing {
    pub struct Thing{}
    #[automock]
    impl Thing {
        pub fn foo(&self) -> u32 {
            // ...
        }
    }
}

cfg_if! {
    if #[cfg(test)] {
        use self::thing::MockThing as Thing;
    } else {
        use self::thing::Thing;
    }
}

fn do_stuff(thing: &Thing) -> u32 {
    thing.foo()
}

#[cfg(test)]
mod t {
    use super::*;

    #[test]
    fn test_foo() {
        let mut mock = Thing::default();
        mock.expect_foo().returning(|| 42);
        do_stuff(&mock);
    }
}

For structs with more than one impl block, see [mock!] instead.

Generic methods

Generic methods can be mocked, too. Effectively each generic method is an infinite set of regular methods, and each of those works just like any other regular method. The expect_* method is generic, too, and usually must be called with a turbofish. The only restrictions on mocking generic methods is that each generic parameter must be 'static, and generic lifetime parameters are not allowed.

#[automock]
trait Foo {
    fn foo<T: 'static>(&self, t: T) -> i32;
}

let mut mock = MockFoo::new();
mock.expect_foo::<i16>()
    .returning(|t| i32::from(t));
mock.expect_foo::<i8>()
    .returning(|t| -i32::from(t));

assert_eq!(5, mock.foo(5i16));
assert_eq!(-5, mock.foo(5i8));

Generic traits and structs

Mocking generic structs and generic traits is not a problem. The mock struct will be generic, too. The same restrictions apply as for mocking generic methods: each generic parameter must be 'static, and generic lifetime parameters are not allowed.

#[automock]
trait Foo<T: 'static> {
    fn foo(&self, t: T) -> i32;
}

let mut mock = MockFoo::<i16>::new();
mock.expect_foo()
    .returning(|t| i32::from(t));
assert_eq!(5, mock.foo(5i16));

Associated types

Traits with associated types can be mocked too. Unlike generic traits, the mock struct will not be generic. Instead, you must specify the associated types when defining the mock struct. They're specified as metaitems to the [#[automock]] attribute.

#[automock(type Key=u16; type Value=i32;)]
pub trait A {
    type Key;
    type Value;
    fn foo(&self, k: Self::Key) -> Self::Value;
}

let mut mock = MockA::new();
mock.expect_foo()
    .returning(|x| i32::from(x));
assert_eq!(4, mock.foo(4));

Multiple and inherited traits

Creating a mock struct that implements multiple traits, whether inherited or not, requires using the [mock!] macro. But once created, using it is just the same as using any other mock object

pub trait A {
    fn foo(&self);
}

pub trait B: A {
    fn bar(&self);
}

mock! {
    // Structure to mock
    C {}
    // First trait to implement on C
    trait A {
        fn foo(&self);
    }
    // Second trait to implement on C
    trait B: A {
        fn bar(&self);
    }
}
let mut mock = MockC::new();
mock.expect_foo().returning(|| ());
mock.expect_bar().returning(|| ());
mock.foo();
mock.bar();

External traits

Mockall can mock traits and structs defined in external crates that are beyond your control, but you must use [mock!] instead of [#[automock]]. Mock an external trait like this:

mock! {
    MyStruct {}     // Name of the mock struct, less the "Mock" prefix
    trait Clone {   // definition of the trait to mock
        fn clone(&self) -> Self;
    }
}

let mut mock1 = MockMyStruct::new();
let mock2 = MockMyStruct::new();
mock1.expect_clone()
    .return_once(move || mock2);
let cloned = mock1.clone();

Static methods

Mockall can also mock static methods. But be careful! The expectations are global. If you want to use a static method in multiple tests, you must provide your own synchronization.

#[automock]
pub trait A {
    fn foo() -> u32;
}

MockA::expect_foo().returning(|| 99);
assert_eq!(99, MockA::foo());

A common pattern is mocking a trait with a construtor method. In this case, you can easily set the mock constructor method to return a mock object.

struct Foo{}
#[automock]
impl Foo {
    fn from_i32(x: i32) -> Self {
        // ...
    }
    fn foo(&self) -> i32 {
        // ...
    }
}

MockFoo::expect_from_i32()
    .returning(|x| {
        let mut mock = MockFoo::default();
        mock.expect_foo()
            .return_const(x);
        mock
    });
let foo = MockFoo::from_i32(42);
assert_eq!(42, foo.foo());

Mocking static methods of generic structs is a little bit tricky. If the static method uses any generic parameters, then those generic parameters must be duplicated as generic parameters of the static method itself. Here's an example:

// A struct like this:
struct Foo<T> {
    // ...
}
impl<T> Foo<T> {
    fn new(t: T) -> Self {
        // ...
    }
}

// Can be mocked like this:
mock! {
    Foo<T: 'static> {
        fn new<T2: 'static>(t: T2) -> MockFoo<T2>;
    }
}

// And used like this:
MockFoo::<u32>::expect_new::<u32>()
    .returning(|_| MockFoo::default());
let mock = MockFoo::<u32>::new(42u32);

One more thing: Mockall normally creates a zero-argument new method for every mock struct. But it won't do that when mocking a struct that already has a method named new.

Foreign functions

Mockall can also mock foreign functions. Like static methods, the expectations are global. And like mocking structs, you'll probably have to fiddle with your imports to make the mock function accessible. Finally, like associated types, you'll need to provide some extra info to [#[automock]] to make it work.

mod ffi {
    #[automock(mod mock;)]
    extern "C" {
        pub fn foo(x: u32) -> i64;
    }
}

cfg_if! {
    if #[cfg(test)] {
        use self::ffi::mock::foo;
    } else {
        use self::ffi::foo;
    }
}

fn do_stuff() -> i64 {
    unsafe{ foo(42) }
}

#[cfg(test)]
mod t {
    use super::*;

    #[test]
    fn test_foo() {
        ffi::mock::expect_foo()
            .returning(|x| i64::from(x + 1));
        do_stuff();
    }
}

Modules

In addition to mocking foreign functions, Mockall can also derive mocks for entire modules of Rust functions, This requires the nightly feature, and it requires the consuming crate to enable feature(proc_macro_hygiene). Usage is the same as when mocking foreign functions, except that the mock module name is automatically derived.

#![feature(proc_macro_hygiene)]
mod outer {
    #[automock()]
    pub(super) mod inner {
        pub fn bar(x: u32) -> i64 {
            // ...
        }
    }
}

cfg_if! {
    if #[cfg(test)] {
        use outer::mock_inner as inner;
    } else {
        use outer::inner;
    }
}

#[cfg(test)]
mod t {
    use super::*;

    #[test]
    fn test_foo_bar() {
        inner::expect_bar()
            .returning(|x| i64::from(x + 1));
        assert_eq!(5, inner::bar(4));
    }
}

Crate features

Mockall has a nightly feature. Currently this feature has three effects:

  • The compiler will produce better error messages.

  • Mocking modules will be enabled.

  • Expectations for methods whose return type implements Default needn't have their return values explicitly set. Instead, they will automatically return the default value.

With nightly enabled, you can omit the return value like this:

#[automock]
trait Foo {
    fn foo(&self) -> Vec<u32>;
}

let mut mock = MockFoo::new();
mock.expect_foo();
assert!(mock.foo().is_empty());

Examples

For additional examples of Mockall in action, including detailed documentation on the autogenerated methods, see [mockall_examples].

[#[automock]]: ../mockall_derive/attr.automock.html [CStr]: https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html [Deref]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html [Expectation]: struct.Expectation.html [Expectations]: struct.Expectations.html [OsStr]: https://doc.rust-lang.org/stable/std/ffi/struct.OsStr.html [Path]: https://doc.rust-lang.org/stable/std/path/struct.Path.html Predicate: trait.Predicate.html [RefExpectation]: struct.RefExpectation.html [RefMutExpectation]: struct.RefMutExpectation.html Sequence: struct.Sequence.html [cfg-if]: https://crates.io/crates/cfg-if expectation!: macro.expectation.html [function]: predicate/fn.function.html [mock!]: ../mockall_derive/macro.mock.html [mockall_examples]: ../mockall_examples/index.html [never]: struct.Expectation.html#method.never predicates: predicate/index.html [return_once]: struct.Expectation.html#method.return_once [return_once_st]: struct.Expectation.html#method.return_once_st [returning_st]: struct.Expectation.html#method.returning_st str: https://doc.rust-lang.org/stable/std/primitive.str.html [times_any]: struct.Expectation.html#method.times_any [times_range]: struct.Expectation.html#method.times_range [times]: struct.Expectation.html#method.times [withf_unsafe]: struct.Expectation.html#method.withf_unsafe [withf]: struct.Expectation.html#method.withf

Re-exports

pub use mockall_derive::mock;
pub use mockall_derive::automock;

Modules

predicate

Predicate factories

Macros

expectation

Generate Expectation and Expectations types for a single method.

Structs

Sequence

Used to enforce that mock calls must happen in the sequence specified.

Traits

Predicate

Trait for generically evaluating a type against a dynamically created predicate function.

PredicateBooleanExt

Predicate extension that adds boolean logic.