Skip to main content

Crate mockem

Crate mockem 

Source
Expand description

Mock any function types in Rust.

Make sure to only use this crate for testing purposes, as it will add a lot of overhead to your code. .mock_once(..) expects a closure that takes the arguments of the function and returns the same return type as the function.

§Basic Usage

On the function you want to mock, add the #[mock] attribute.

#[cfg_attr(test, mockem::mock)]
fn foo() -> String {
    format!("foo")
}

fn bar() -> String {
    format!("Hello, {}!", foo())
}

#[test]
fn test_fn() {
    use mockem::MockCall;

    foo.mock_once(|| "mockem".to_owned());
    foo.mock_once(|| "mockem2".to_owned());

    assert_eq!(&bar(), "Hello, mockem!");
    assert_eq!(&bar(), "Hello, mockem2!");

    // works normally after all mocks are used
    assert_eq!(&bar(), "Hello, foo!");
}

§Mocking Repeatedly

If you want to mock a function more than once or indefinitely, use mock_repeat instead of mock_once.

mock_repeat takes an Option<usize> as its first argument, which is the number of times to mock the function;

None means to mock the function indefinitely.

#[cfg_attr(test, mockem::mock)]
fn foo(a: &str) -> String {
    format!("{a}")
}

fn bar(a: &str) -> String {
    format!("Hello, {}!", foo(a))
}

#[test]
fn test_fn() {
    use mockem::{MockCall, ClearMocks};

    foo.mock_repeat(None, |a| format!("mocked {a}"));

    assert_eq!(&bar("bar"), "Hello, mocked bar!");
    assert_eq!(&bar("foo"), "Hello, mocked foo!");
    assert_eq!(&bar("baz"), "Hello, mocked baz!");

    // this clears all mocks, which will stop the indefinite mock
    foo.clear_mocks();

    assert_eq!(&bar("baz"), "Hello, baz!");
}

§Impl Blocks

If you want to mock impl methods, add the #[mock] attribute to the impl block. Do the same for impl trait methods.

This will mock all methods in the impl block.

struct Foo;

#[cfg_attr(test, mockem::mock)]
impl Foo {
    fn foo(&self) -> String {
        format!("foo")
    }
}

trait Baz {
    fn baz(&self) -> String;
}

#[cfg_attr(test, mockem::mock)]
impl Baz for Foo {
    fn baz(&self) -> String {
        format!("baz")
    }
}

fn bar() -> String {
    format!("Hello, {} and {}!", Foo.foo(), Foo.baz())
}

#[test]
fn test_fn() {
    use mockem::MockCall;

    Foo::foo.mock_once(|_| "mockem".to_owned());
    Foo::baz.mock_once(|_| "mockem2".to_owned());

    assert_eq!(&bar(), "Hello, mockem and mockem2!");
}

§Async Functions

Async functions are also supported.

use async_trait::async_trait;

struct Foo;

#[cfg_attr(test, mockem::mock)]
impl Foo {
    async fn foo(&self) -> String {
        format!("foo")
    }
}

#[async_trait]
trait Baz {
    async fn baz(&self) -> String;
}

// also works with async_trait
// but you must place #[mock] above #[async_trait]
#[cfg_attr(test, mockem::mock)]
#[async_trait]
impl Baz for Foo {
    async fn baz(&self) -> String {
        format!("baz")
    }
}

async fn bar() -> String {
    format!("Hello, {} and {}!", Foo.foo().await, Foo.baz().await)
}

#[test]
fn test_fn() {
    use mockem::MockCall;

    Foo::foo.mock_once(|_| "mockem".to_owned());
    Foo::baz.mock_once(|_| "mockem2".to_owned());

    assert_eq!(&bar().await, "Hello, mockem and mockem2!");
}

Traits§

ClearMocks
Clear all mocked return values related to this function. You can use this if you have a recursive mock closure that continously mocks.
MockCall
Auto-implemented trait for mocking return values of functions.

Functions§

clear_mocks
Clear all mocks in the ThreadLocal; only necessary if tests share threads

Attribute Macros§

mock