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

SetupAllProperties 2nd property not mocked #438

Closed
dosfx opened this issue Sep 5, 2017 · 3 comments
Closed

SetupAllProperties 2nd property not mocked #438

dosfx opened this issue Sep 5, 2017 · 3 comments
Labels

Comments

@dosfx
Copy link

dosfx commented Sep 5, 2017

New to moq, so its probably me but I've got an interface that I'm mocking with 2 get properties of another interface. When I call SetupAllProperties on the mock, the 2nd get property doesn't appear to get mocked. All I can think is that it is due to it being the same type?

example:

interface IResult
{
    ISubResult Part1 { get; }
    string OtherProperty { get; set; }
    ISubResult Part2 { get; }
}

resultMock = new Mock<IAuthPipeResult> { DefaultValue = DefaultValue.Mock };
resultMock.SetupAllProperties();

resultMock.Object.Part1.Name = "value";  // This is fine
resultMock.Object.Part2.Name = "value";  // Part2 is null, throws exception

Currently my workaround is to call resultMock.SetupAllProperties(); and then call resultMock.SetupProperty(m => m.Part1.Name); but I feel like I must be missing something

Thanks for reading

@stakx stakx added the bug label Sep 16, 2017
@stakx
Copy link
Contributor

stakx commented Sep 16, 2017

@dosfx, thanks for reporting! You're not missing anything. This is a bug. I'm surprised that noone's run into this before.

Until this bug is fixed, you're better off not using SetupAllProperties in this particular case. Instead do what you've already figured out yourself and set up the properties individually, e.g.:

resultMock.SetupGet(result => result.Part1).Returns(Mock.Of<ISubResult>());
resultMock.SetupGet(result => result.Part2).Returns(Mock.Of<ISubResult>());

Some background:

mock.SetupAllProperties sets up properties recursively. There's some logic in Moq to prevent infinite loops during that process (in case of recursive types). The problem here is that the loop detection logic is not accurate enough. When SetupAllProperties sets up Part1, it notes down that it has mocked something of type ISubResult. When it gets to Part2, it sees that it is dealing with an ISubResult again, and in order to prevent the possibility of a recursion-based infinite loop, it short-cuts by setting up Part2 to simply return null. This behaviour does not make any sense in your scenario.

(For better understanding why that behaviour is there at all, consider the below example where it indeed prevents SetupAllProperties from going into an infinite loop:)

public interface IPing { IPong Pong { get; } }
public interface IPong { IPing Ping { get; } }
var pingMock = new Mock<IPing>();
pingMock.SetupAllProperties();

The loop detection logic could be fixed by making it also consider recursion depth along with the property types.

@stakx
Copy link
Contributor

stakx commented Sep 16, 2017

@dosfx, this will be fixed in the next release of Moq (version >4.7.99).

@stakx stakx closed this as completed Sep 16, 2017
@dosfx
Copy link
Author

dosfx commented Sep 17, 2017 via email

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

No branches or pull requests

2 participants