7 releases

0.2.4 Jun 22, 2024
0.2.3 Jan 5, 2024
0.1.1 Jan 4, 2024

#220 in Testing

Download history 64/week @ 2024-08-08 63/week @ 2024-08-15 56/week @ 2024-08-22 36/week @ 2024-08-29 28/week @ 2024-09-05 62/week @ 2024-09-12 192/week @ 2024-09-19 53/week @ 2024-09-26 4/week @ 2024-10-03 12/week @ 2024-10-10 10/week @ 2024-10-17 41/week @ 2024-10-24 35/week @ 2024-10-31 5/week @ 2024-11-07 1/week @ 2024-11-21

53 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

~220–660KB
~16K SLoC