Как я могу использовать It.IsAny в качестве параметра? - PullRequest
0 голосов
/ 14 февраля 2019

У меня есть тестовый класс, вызывающий макет MyClass, у меня Setup оба DoStuffA и DoStuffB ранее.

Я пытался обернуть несколько вызовов Verify вметод, подобный так:

void VerifyMany(int input)
{
    _myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
    _myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}

Если я вызову мой метод с It.IsAny<int>() в качестве ввода - VerifyMany(It.IsAny<int>()) - мои тесты не пройдут, он будет работать, если я вызову метод Verify напрямуюwith It.IsAny:

_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());

Я понимаю из ответа на вопрос этот , что Moq обрабатывает It.IsAny иначе в выражении, если указано для Setup / Verify, есть ли обходной путь дляэто?

Ответы [ 2 ]

0 голосов
/ 14 февраля 2019

Причина, по которой это не работает:

void VerifyMany(int input)
{
    _myClassMock.Verify(ic => ic.DoStuffA(input), Times.Once());
    _myClassMock.Verify(ic => ic.DoStuffB(input), Times.Once());
}

Это потому, что It.IsAny<int>() (при простом вызове) возвращает 0. Таким образом, по сути, когда VerifyMany вызывается с It.IsAny<int>(), вы передаетеОт 0 до VerifyMany.Что, в свою очередь, означает, что DoStuffA(0) и DoStuffB(0) проверены (не любое целочисленное значение, как вы, вероятно, предполагали).

Другой вызов:

_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
_myClassMock.Verify(ic => ic.DoStuffB(It.IsAny<int>()), Times.Once());

Работает, потому что ic => ic.DoStuffA(It.IsAny<int>() часть никогда не вызывается напрямую.Оно превращается в дерево выражений, и Мок только гуляет (или посещает, если хотите), это дерево выражений.Это означает, что он найдет It.IsAny<int>() в Дереве выражений, а затем сможет проверить вызов DoStuffA (который он также нашел в том же дереве выражений) с любым целочисленным значением.(для более подробной информации о деревьях выражений, не стесняйтесь прочитать это )

Вы можете сделать эту полуработу, создав метод, который абстрагирует вызов от Verify и принимает выражение какИтак:

void VerifyOnce(Expression<Action<ClassMockIsBasedOn>> callToVerify)
{
    _myClassMock.Verify(callToVerify, Times.Once());
}

Что позволяет вам так называть:

VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>())

Вы также можете расширить пример VerifyOnce для принятия нескольких выражений.Это позволило бы вам проверить DoStuffA и DoStuffB в одной строке:

void VerifyOnce(params Expression<Action<ClassMockIsBasedOn>>[] callsToVerify)
{
    foreach(var callToVerify in callsToVerify) 
    {
        _myClassMock.Verify(callToVerify, Times.Once());
    }
}

Это позволило бы выполнить вызов следующим образом:

VerifyOnce(ic => ic.DoStuffA(It.IsAny<int>(),
           ic => ic.DoStuffB(It.IsAny<int>());

И, конечно, вы могли бы заменитьClassMockIsBasedOn с общим.И добавьте перегрузку, которая учитывает методы, которые возвращают значения (вместо того, чтобы быть пустыми) или принимают более одного параметра, как предложил Бретт в комментариях.

0 голосов
/ 14 февраля 2019

It.IsAny только позволяет Moq сопоставлять будущие вызовы вызовов методов, если они используются в конструкции Setup, вы не можете сделать это с Verify или Assert, если ваш Setup не установлен It.IsAny еще.Потому что It.IsAny всегда возвращает значение по умолчанию для ввода.

Поэтому, если вы хотите использовать It.IsAny при Verify, вы должны Setup для целевого метода сначала:

Правильно

_myClassMock.Setup(ic => ic.DoStuffA(It.IsAny<int>())).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());

Неправильно

_myClassMock.Setup(ic => ic.DoStuffA(1)).Returns(// Something here);
_myClassMock.Verify(ic => ic.DoStuffA(It.IsAny<int>()), Times.Once());
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...