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

Specifying the expected number of occurrences in IsIn() #1214

Closed
madstt opened this issue Oct 27, 2021 · 4 comments
Closed

Specifying the expected number of occurrences in IsIn() #1214

madstt opened this issue Oct 27, 2021 · 4 comments

Comments

@madstt
Copy link

madstt commented Oct 27, 2021

In a verification step, I would like to specify the number of times an expected value should occur.

Using the current version:

serviceMock.Verify(service => service.GetPet(It.IsIn(expectedListOfValues)), Times.Once);

But that does not catch cases where you need to verify an exact number of times an expected value is allowed, it just verifies that the value is in the list.

I did an honest attempt to make this possible. Since the It class is static and sealed, it is not possible to create an extension method nor inherit from It, so I made my static class and method:

serviceMock.Verify(service => service.GetPet(It.IsExactlyIn(expectedListOfValues, 1)), Times.Once);

This would require that the mock is only called once for either of the expected values in expectedListOfValues.

I took the current implementation of IsIn() and added a requirement:

public static TValue IsExactlyIn<TValue>(IEnumerable<TValue> items, int times)
    where TValue : class
{
    return Match.Create<TValue>(value => items.Contains(value) && items.Count(item => item == value) == times);
}

I'm wondering whether I should create a PR for this or you don't see any reason to add this Moq?

@stakx
Copy link
Contributor

stakx commented Oct 27, 2021

It is sometimes a pity that static classes cannot be extended that way, right? Nevertheless, I think it doesn't make sense to add all possible kinds of specific predicates to Moq's It class. We have the basic constructs in place that can be used to create further predicates – It.Is and custom argument matchers – and my vote goes towards leaving it at that and keep more specific predicates in user code.

(There are some fairly specific It methods that, judging from retrospective, perhaps shouldn't be in the core library either. Nothing to be done about those, removing them isn't worth a breaking change IMHO.)

@madstt
Copy link
Author

madstt commented Oct 27, 2021

Ok, that sounds reasonable. Is it actually possible to create the same logic using current constructs and custom argument matchers? If so, could show an example?

@stakx
Copy link
Contributor

stakx commented Oct 27, 2021

I think you've already figured out how to use custom matchers for this. But here goes.

You can replace It.IsIn(xs) with It.Is(x => xs.Contains(x)), right?

From there, it should be easy to adjust the predicate so it checks for n occurrences instead; say, It.Is(x => xs.Count(y => y == x) == n).

You could then wrap this up similar to how you've done already:

static T IsExactlyIn<T>(IEnumerable<T> items, int times)
{
    return It.Is(x => items.Count(y => y == x) == times);
}

(I probably wouldn't even go down the custom matcher path for this; wrapping It.Is seems perfectly sufficient.)

@madstt
Copy link
Author

madstt commented Oct 27, 2021

Thank you.

I'll close this.

@madstt madstt closed this as completed Oct 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants