mockall icon indicating copy to clipboard operation
mockall copied to clipboard

Support default implementation

Open oblique opened this issue 2 years ago • 3 comments

I would like to be able to use the default implementation of a method. In #94 you had a valid point that every method must be driven by expectations, however maybe a Expectation::default_fn can be introduced.

This is an example:

use mockall::automock;

#[automock]
trait Foo {
    fn bar(&self) -> i32;

    fn foo(&self) -> i32 {
        self.bar() + 1
    }
}

fn main() {
    let mut mock = MockFoo::new();

    mock.expect_bar().return_const(123);
    mock.expect_foo().default_fn();

    assert_eq!(mock.foo(), 124);
}

What do you think?

oblique avatar Feb 01 '23 16:02 oblique

I think you can already achieve what you want by using mock! instead of #[automock]. Try this:

trait Foo {
    fn bar(&self) -> i32;

    fn foo(&self) -> i32 {
        self.bar() + 1
    }
}
mock!{
    Foo {}
    impl Foo for Foo {
        fn bar(&self) -> i32;
    }
}

Also, if I were to add a new feature for this, I wouldn't use the default_fn method as you suggest, because that wouldn't work well with mock!. Instead, I think it would be better to decorate the method with an attribute like #[nomock], similarly to the #[concretize] attribute described at https://github.com/asomers/mockall/discussions/409.

asomers avatar Feb 01 '23 17:02 asomers

what about detecting if a trait method SomeTrait::some_method(x) has a body, and if it does, simply create a new method like SomeTrait::some_method__default(x) which contains the method body.

Then if the user wants, they can simply call the default impl in the expectation for the method

let mock = MockSomeTrait::new()
mock.expect_some_method().returning(MockSomeTrait::some_method__default)

That way we don't have to have multiple usages of mock!, or no_mock, mock_all can just stash the default under some well-known name.

I could see some issues around complicated lifetimes and other things Mockall currently deals with tho.

DanielJoyce avatar Aug 24 '23 22:08 DanielJoyce

No, that wouldn't work. It might work for a few simple cases, but it would be too fragile, because:

  • The method body may assume that Self == MyStruct instead of MockMyStruct
  • Mockall puts that kind of stuff in a submodule, which may break use paths used by the method body.

asomers avatar Aug 24 '23 23:08 asomers