Giter Club home page Giter Club logo

Comments (6)

AntonVasserman avatar AntonVasserman commented on September 3, 2024 1

You have two invocations, so your predicate runs twice (once per invocation) per Verify call. Am I still misunderstanding?

Verify cannot magically know which invocations will match the predicate and which ones won't. It uses the predicate to determine that, which is why the predicate runs once per invocation.

Okay that now makes total sense... The issue is indeed with the Assert throwing.
Since we indeed have to go through all the invocations to validate the predicate, once we execute the validation with the wrong input the Assert will throw.

Thank you very much for the quick help and responses, and for clarifying the case here!

from moq4.

stakx avatar stakx commented on September 3, 2024

Hi @AntonVasserman. I haven't run your code, but by just looking at it, I suspect the problem doesn't lie with Moq, but with your usage of Assert.Equal inside ValidateModel. Assert.Equal may throw exceptions. The predicate function passed to It.Is<> OTOH should never to throw, but simply return a bool indicating whether a positive match was made or not. That is, your ValidateModel method should convert thrown exceptions to a return value of false (or even more simply, just use object.Equals instead of Assert.Equal); then the rest of your code should work as expected.

(Also, if it isn't self-evident: mock.Verify has to run the predicate against all invocations to figure out how many of them match the predicate; that is, you should expect that your predicate gets run against invocations that may not match it. That's why the use of a possibly-throwing Assert.Equal inside the predicate is an error.)

from moq4.

AntonVasserman avatar AntonVasserman commented on September 3, 2024

@stakx No I don't think this is related.
The only reason ValidateModel throws is because there is a second execution of the It.Is<> for some reason.
I have changed the code to this:

public class Program
{
    private static int _count = 0;

    public static void Main(string[] args)
    {
        Mock<ISomeInterface> mock = new();
        SomeClass someClass = new(mock.Object);
        SomeModel someModel1 = new() { Value = 1 };
        SomeModel someModel2 = new() { Value = 2 };
        List<SomeModel> list = new List<SomeModel> { someModel1, someModel2 };
        someClass.BatchedMethod(list);

        // This first call actually verifies both invocations
        mock.Verify(m => m.SomeMethod(It.Is<SomeModel>(actualModel => ValidateModel(actualModel, someModel1))), Times.Exactly(2));
        // This second call is never even called since the first one fails on its second run due to 'actualModel' being 'someModel2'...
        // mock.Verify(m => m.SomeMethod(It.Is<SomeModel>(actualModel => ValidateModel(actualModel, someModel2))), Times.Once());

        Console.WriteLine($"Finished: {_count}");
    }

    private static bool ValidateModel(SomeModel actualModel, SomeModel originalModel)
    {
        // Assert.Equal(actualModel.Value, originalModel.Value);
        if (originalModel.Value == 1) _count++;
        return true;
    }
}

And this is the value I get:
image
This is even though we, supposedly, call mock.Verify(m => m.SomeMethod(It.Is<SomeModel>(actualModel => ValidateModel(actualModel, someModel1))), Times.Exactly(2)); once, so it clearly means that the method is called twice for some reason.
(Note I had to change Times.Once to Times.Exactly(2) so it won't throw...)

from moq4.

stakx avatar stakx commented on September 3, 2024

You have two invocations, so your predicate runs twice (once per invocation) per Verify call. Am I still misunderstanding?

Verify cannot magically know which invocations will match the predicate and which ones won't. It uses the predicate to determine that, which is why the predicate runs once per invocation.

from moq4.

stakx avatar stakx commented on September 3, 2024

Note I had to change Times.Once to Times.Exactly(2) so it won't throw...

This doesn't match with your code comments in the example shown:

// This first call actually verifies both invocations
mock.Verify(m => m.SomeMethod(It.Is<SomeModel>(actualModel => ValidateModel(actualModel, someModel1))), Times.Exactly(2));
// This second call is never even called since the first one fails on its second run due to 'actualModel' being 'someModel2'...
// mock.Verify(m => m.SomeMethod(It.Is<SomeModel>(actualModel => ValidateModel(actualModel, someModel2))), Times.Once());

from moq4.

stakx avatar stakx commented on September 3, 2024

You're welcome. Glad I could help with clearing things up.

from moq4.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.