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

add It.Ignore for AnyMatcher #790

Closed
wants to merge 1 commit into from
Closed

add It.Ignore for AnyMatcher #790

wants to merge 1 commit into from

Conversation

helloserve
Copy link

While experimenting with .NET Core 3.0 preview I ran into a problem where they were no longer boxing an internal class to object to the ILogger.Log<TState> abstraction. This means that I can no longer Setup or Verify against that abstraction, since It.IsAny<>() has to exactly match the invocation types. See dotnet/extensions#1319 for the details on this. And really, as we discover more changes in 3.0 Preview I expect to see more of these decisions impacting us.

The only solution I can think of is to have a way to completely short-circuit on specific parameters (who's types you cannot see) by explicitly choosing to do so via a new It.Ignore<>() method.

I don't expect you to merge this in to 4.0 at all, but rather to see it as a feature request for 5.0 via implementation. However if 3.0 is finalized and lands before Moq 5.0 ships I expect a few projects will be broken when they upgrade. At least then you'll have this to decide to include or not.

@helloserve helloserve changed the title add It.IsIgnore for AnyMatcher add It.Ignore for AnyMatcher Mar 29, 2019
@stakx
Copy link
Contributor

stakx commented Mar 29, 2019

Hi @helloserve, thanks for raising this issue (well, PR actually). I'll review it soon and look at .NET Core 3 a little more closely.

In the meantime, remember that you don't need to wait for Moq to have a suitable matcher, you can simply create a custom matcher yourself, using Match.Create:

static T Ignore<T>()
{
    return Match.Create(x => true, () => Ignore<T>());
}

@helloserve
Copy link
Author

Ah right. Now I feel kinda dumb. I did not know about Custom matchers. Thanks!

@stakx
Copy link
Contributor

stakx commented May 7, 2019

@helloserve, sorry for the long silence, I've actually been looking into this several weeks ago and seen that custom matchers don't help in your case, after all. I can see how this PR would help solve some situations that Moq currently doesn't have any other solution for.

On the other hand, I'd really prefer that we didn't have to add this It.Ignore matcher, mainly for the reason that it might be rather confusing to have it alongside It.IsAny, as the difference between these two might be too subtle for most users to grasp easily.

I've been thinking that we might add it but keep it from showing up in IntelliSense using [EditorBrowsable(EditorBrowsableState.Advanced)] trickery, but that feels like adding something just because we haven't solved another, larger problem in Moq in a clean and thorough manner.

Do you see any other solutions for what you want to achieve?

@helloserve
Copy link
Author

helloserve commented May 9, 2019

I completely feel the same way about it. Having to ignore a parameter seems counter intuitive to setting up a mock, and matching invocations specifically is crucial to prevent false-positive results. Or at least, I can totally see how false positives can occur when using It.Ignore() wantonly. This is why the decision to internalize types used on the public side of (the ILogger) abstractions is pretty disappointing to me.

I think the only really clean solution here is if C# can introduce the bottom keyword - see here. Using it as It.IsAny<IReadOnlyList<bottom>>() for example would match the type in this particular instance for the ILogger invocation. I do however find that this is a pretty advanced concept. I had to reread that proposal discussion probably 5 times...

So while we wait for that, It.Ignore() is really just a temporary workaround tbh. I made the PR in a moment of frustration and used the word feature, but really it's all it is. I'm not sure how to decorate that effectively, or how long we'll wait. Having it as an undocumented feature doesn't feel right though. Perhaps just mark it as deprecated straight out of the gate? Or perhaps we can change the name to be It.IgnoreType() to be slightly more specific?

Personally I don't believe that Moq itself has a larger problem to solve here. The implementation policies of the Core framework is what is changing and causing this, after all. That said, the guy that responded to my issue on the abstraction package said

It looks like Moq should support bottom-nothing-never like type in its generic type parameter DSL dotnet/csharplang#538 to allow match any generic (and they can do that with no language level support)

How to do that without having bottom, or know all the (internal or not) types is beyond me thus far. I can help you investigate that if you want?

@stakx
Copy link
Contributor

stakx commented May 9, 2019

It looks like Moq should support bottom-nothing-never like type in its generic type parameter DSL dotnet/csharplang#538 to allow match any generic (and they can do that with no language level support)

How to do that without having bottom, or know all the (internal or not) types is beyond me thus far. I can help you investigate that if you want?

I believe that #343 is about just that.

It.Ignore() is really just a temporary workaround tbh.

Agreed. And as such, we shouldn't add it to Moq because once added, it will no longer be able to stay "temporary"—removing it again will be a breaking change.

I suggest that we don't merge this PR for the above reasons and instead keep at #343.

@helloserve helloserve closed this May 9, 2019
@devlooped devlooped locked and limited conversation to collaborators Sep 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants