6 releases

0.2.3 Jan 5, 2024
0.2.2 Jan 5, 2024
0.1.1 Jan 4, 2024

#168 in Testing

Download history 1/week @ 2023-12-29 3/week @ 2024-01-05 3/week @ 2024-02-02 39/week @ 2024-02-09 60/week @ 2024-02-16 13/week @ 2024-02-23 2/week @ 2024-03-01 2/week @ 2024-03-08 1/week @ 2024-03-15 13/week @ 2024-03-22 23/week @ 2024-03-29 24/week @ 2024-04-05

61 downloads per month

MIT/Apache

24KB
328 lines

Mock'em

github crates.io docs.rs

Mock any function in Rust.

Make sure to only use this crate for testing purposes, as it will add a lot of overhead to your code.

Basic Usage

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

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

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

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

    foo.mock_once(|a| format!("mocked {a}"));

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

    // function works normally after mock return value is returned
    assert_eq!(&bar(), "Hello, bar!");
}

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!");
}

Dependencies

~0.4–0.9MB
~21K SLoC