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

Interface Default methods are ignored #972

Closed
hahn-kev opened this issue Feb 13, 2020 · 2 comments · Fixed by #1130
Closed

Interface Default methods are ignored #972

hahn-kev opened this issue Feb 13, 2020 · 2 comments · Fixed by #1130
Assignees
Milestone

Comments

@hahn-kev
Copy link
Contributor

I'm not sure if this would be considered a bug, but I'd think it would work the same as mocking an abstract class.

Example

interface ITest
{
    string CallMe();

    string CallMeDefault()
    {
        return CallMe();
    }
}

[Fact]
public void DefaultFails()
{
    var mock = new Mock<ITest>(MockBehavior.Loose);
    mock.Setup(t => t.CallMe()).Returns("hello");
    Assert.NotNull(mock.Object.CallMeDefault());
}

My interface has the method CallMeDefault which has an implementation, however when I mock that interface it gets overridden and calling that method returns null instead of what CallMe returns as I'd expect. I think ideally this would follow the CallBase setting, however it doesn't seem like it does.

@stakx
Copy link
Contributor

stakx commented Feb 13, 2020

Before Moq can support default interface methods, DynamicProxy must add support for them; see castleproject/Core#447.

@stakx
Copy link
Contributor

stakx commented Jan 17, 2021

@hahn-kev: OK, I think this can be made to work. You'll have to configure CallBase behavior for your CallMeDefault interface method, either at the setup level:

 var mock = new Mock<ITest>(MockBehavior.Loose);
 mock.Setup(t => t.CallMe()).Returns("hello");
+mock.Setup(t => t.CallMeDefault()).CallBase();
 Assert.NotNull(mock.Object.CallMeDefault());

or at the mock level (whatever is a better fit for your tests):

-var mock = new Mock<ITest>(MockBehavior.Loose);
+var mock = new Mock<ITest>(MockBehavior.Loose) { CallBase = true };
 mock.Setup(t => t.CallMe()).Returns("hello");
 Assert.NotNull(mock.Object.CallMeDefault());

In terms of default interface implementations, .CallBase() shall call the most specific override.

@stakx stakx added this to the 4.16.1 milestone Jan 17, 2021
mburumaxwell pushed a commit to faluapp/falu-dotnet that referenced this issue Jun 12, 2021
Bumps [Moq](https://github.com/moq/moq4) from 4.16.0 to 4.16.1.

#Changelog

*Sourced from [Moq's changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md).*

> ## 4.16.1 (2021-02-23)
>
> #### Added
>
> * `CallBase` can now be used with interface methods that have a default interface implementation. It will call [the most specific override](https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods#the-most-specific-override-rule). (@stakx, [#1130](devlooped/moq#1130))
>
> #### Changed
>
> * Improved error message formatting of `It.Is` lambda expressions that capture local variables. (@bfriesen, [#1140](devlooped/moq#1140))
>
> #### Fixed
>
> * `AmbiguousMatchException` raised when interface has property indexer besides property in VB. (@mujdatdinc, [#1129](devlooped/moq#1129))
> * Interface default methods are ignored (@hahn-kev, [#972](devlooped/moq#972))
> * Callback validation too strict when setting up a task's `.Result` property (@stakx, [#1132](devlooped/moq#1132))
> * `setup.Returns(InvocationFunc)` wraps thrown exceptions in `TargetInvocationException` (@stakx, [#1141](devlooped/moq#1141))

#Commits

- [`fc484fb`](devlooped/moq@fc484fb) Update version to 4.16.1
- [`0ddfdb8`](devlooped/moq@0ddfdb8) `Returns(InvocationFunc)` shouldn't throw `TargetInvocationException`
- [`f36d3e8`](devlooped/moq@f36d3e8) Merge pull request [#1140](devlooped/moq#1140) from bfriesen/lambda_closure_support
- [`e96804f`](devlooped/moq@e96804f) Update the changelog
- [`5ae449c`](devlooped/moq@5ae449c) Exclude name of the closure class
- [`8a2d2ed`](devlooped/moq@8a2d2ed) Add test for closure access
- [`cf5af87`](devlooped/moq@cf5af87) Format lambda expression variables
- [`5b10a8c`](devlooped/moq@5b10a8c) Add test for lamba matcher variables
- [`653db31`](devlooped/moq@653db31) Some minor renames for consistency
- [`fc73131`](devlooped/moq@fc73131) Add missing copyright notices
- Additional commits viewable in [compare view](devlooped/moq@v4.16.0...v4.16.1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants