Проверка того, вызывался ли метод дважды с разными аргументами

#c# #moq

Вопрос:

Мне нужно убедиться, что метод был вызван 2 раза с определенными аргументами:

 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);
}
 

Вот моя часть проверки, в которой оба утверждения потерпели неудачу:

 // 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
);
 

Таким образом, проблема заключается в том, что оба вызова внутри метода Execute используют один и тот же аргумент, который к моменту выполнения утверждения содержит 2 в качестве своего внутреннего значения.

Вопрос в том, как сделать макет, чтобы каким-то образом «записать» аргументы, чтобы они были правильно оценены?

Ниже приведен полный список:

 [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;
    }
}


 

Я действительно ценю любую обратную связь, спасибо!

Ответ №1:

Вы можете установить обратный вызов при настройке DoSomething , чтобы отслеживать приращение значения счетчика.

 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  ;
    });
 

Затем проверьте эти звонки:

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