Skip to content

Interface Default methods are ignored #972

New issue

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

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

Already on GitHub? # to your account

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)
@devlooped devlooped locked and limited conversation to collaborators Sep 5, 2024
# for free to subscribe to this conversation on GitHub. Already have an account? #.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants