Skip to content

Mocking a function taking an FnMut closure incompatible with concretize #577

Closed
@vlovich

Description

@vlovich

Tried on Stackoverflow but I think this won't get the right eyes there. I have a trait I'm trying to mock that looks like below. It has a for_each method that takes an FnMut and invokes it on all items of interest. UnderTest is the thing I'm trying to test where I give it a mocked Foo instance and it calls for_each and does something with each element. The problem is that when I use concretize, the returning expectation receives a &dyn FnMut instead of &mut dyn FnMut meaning I can't invoke the callback to invoke the closure do_something provides. If I get rid of #[concretize] & make F: 'static for for_each, then I get an invokable function, but then do_something won't compile because &mut sum doesn't have static lifetime (i.e. the static lifetime is purely for mocking & adds requirements I don't need when I don't mock).

Is there a better way?

#[cfg_attr(test, automock)]
trait Foo {
    #[cfg_attr(test, concretize)]
    fn for_each<F>(&self, processor: F)
    where
        Self: Sized,
        F: FnMut(&u32);
}

#[derive(Default)]
struct UnderTest;

impl UnderTest {
   fn do_something<F: Foo>(&self, foo: &F) {
     let mut sum = 0;
     let sum_mut = &mut sum;
     foo.for_each(|x| {
         *sum_mut += *x;
     })
     eprintln!("Sum of all numbers is {sum}");
   }
}

#[cfg(test)]
#[test]
fn do_something() {
   let mut foo = MockFoo::new();
   foo.expect_for_each().times(1).returning(|cb| {
     cb(&0);
     cb(&1);
   });

   let t = UnderTest::default();
   t.do_something(&foo);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions