7 releases

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

#174 in Testing

Download history 325/week @ 2024-06-22 170/week @ 2024-06-29 130/week @ 2024-07-06 166/week @ 2024-07-13 202/week @ 2024-07-20 176/week @ 2024-07-27 100/week @ 2024-08-03 46/week @ 2024-08-10 54/week @ 2024-08-17 68/week @ 2024-08-24 24/week @ 2024-08-31 40/week @ 2024-09-07 101/week @ 2024-09-14 158/week @ 2024-09-21 28/week @ 2024-09-28 3/week @ 2024-10-05

296 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

~245–690KB
~16K SLoC