Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support default implementation #454

Open
oblique opened this issue Feb 1, 2023 · 3 comments
Open

Support default implementation #454

oblique opened this issue Feb 1, 2023 · 3 comments
Labels
enhancement New feature or request

Comments

@oblique
Copy link

oblique commented Feb 1, 2023

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?

@asomers
Copy link
Owner

asomers commented Feb 1, 2023

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 #409.

@asomers asomers added the enhancement New feature or request label Feb 1, 2023
@DanielJoyce
Copy link

DanielJoyce commented Aug 24, 2023

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.

@asomers
Copy link
Owner

asomers commented Aug 24, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

3 participants