Testing whether a method was called twice with different arguments

Viewed 525

I need to verify that a method has been invoked 2 times with specific arguments:

public void Execute()
{
    Counter с = new Counter(1);
    
    // Basically, I need to verify that DoSomething method was called twice: 
    // First time with an argument, which internal value is 1... 
    _subject.DoSomething(с);
    
    c.Increment();
    
    // ... and the second time - with internal value of 2
    _subject.DoSomething(c);
}

Here is my verification part, with both assertions failing:

// Fails with message "Expected invocation on the mock once, but was 0 times" 
mock.Verify(
    m => m.DoSomething(
        It.Is<Counter>(
            x => x.GetValue() == 1
        )
    ), 
    Times.Once
);

// Fails with message "Expected invocation on the mock once, but was 2 times" 
mock.Verify(
    m => m.DoSomething(
        It.Is<Counter>(
            x => x.GetValue() == 2
        )
    ), 
    Times.Once
);

So the problem is that both invocations inside the Execute method use the same argument, which by the time of performing the assertion contains 2 as its internal value.

The question is how to make the mock to "record" the arguments somehow, so that they are evaluated correctly?

Below is the full listing:

[Test]
public void CheckSomething()
{
    Mock<Subject> mock = new Mock<ISubject>();
    mock.Setup(m => m.DoSomething(It.IsAny<Counter>()));
    var myService = new MyService(mock.Object);

    myService.Execute();

    mock.Verify(m => m.DoSomething(It.Is<Counter>(x => x.GetValue() == 2)), Times.Once);
    mock.Verify(m => m.DoSomething(It.Is<Counter>(x => x.GetValue() == 1)), Times.Once);
}

public interface ISubject
{
    public void DoSomething(Counter с);
}

public class Subject : ISubject
{
    public void DoSomething(Counter с)
    {
        // doesn't matter
    }
}

public class MyService
{
    private readonly ISubject _subject;

    public MyService(ISubject subject)
    {
        _subject = subject;
    }

    public void Execute()
    {
        Counter с = new Counter(1);
        _subject.DoSomething(с);
        с.Increment();
        _subject.DoSomething(с);
    }
}

public class Counter
{
    private int _val;

    public Counter(int val)
    {
        _val = val;
    }

    public void Increment()
    {
        _val++;
    }

    public int GetValue()
    {
        return _val;
    }
}


I really appreciate any feedback, thanks!

1 Answers

You can set a callback when setting up your DoSomething to track the increment of counter's value.

int counterEqual1 = 0;
int counterEqual2 = 0;

mock.Setup(m => m.DoSomething(It.IsAny<Counter>()))
    .Callback<Counter>(counter =>
    {
        if (counter.GetValue() == 1)
            counterEqual1++;
        else if (counter.GetValue() == 2)
            counterEqual2++;
    });

Then verify those calls:

mock.Verify(m => m.DoSomething(It.IsAny<Counter>()), Times.Exactly(2));
Assert.That(counterEqual1, Is.EqualTo(1));
Assert.That(counterEqual2, Is.EqualTo(1));
Related