Почему Moq устанавливает / проверяет совпадение, когда It.Is ... () вызывается из анонимной функции - PullRequest
4 голосов
/ 28 октября 2011

Я столкнулся с каким-то странным поведением при попытке упростить создание довольно сложного дерева выражений для настройки / проверки соответствия с помощью moq.

Предположим, я издеваюсь над простым интерфейсом, определенным ниже

public interface IService
{
    int Send(int value);
}

Следующий код представляет 5 тестов.Один тест для каждого из mockSender.Setup(...).Может кто-нибудь объяснить, почему тесты, помеченные как неудачные, терпят неудачу?

[Test]
public void TestInlineSetup()
{
    const int expected = 5;
    var mockSender = new Mock<IService>(MockBehavior.Loose);

    //passes
    mockSender.Setup(s => s.Send(It.IsAny<int>())).Returns(expected);

    //fails
    var sendMatch = It.IsAny<int>();
    mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);

    //passes
    mockSender.Setup(s => s.Send(SendMatchFromMethod())).Returns(expected);

    //fails
    var sendMatch = SendMatchFromMethod();
    mockSender.Setup(s => s.Send(sendMatch)).Returns(expected);

    //fails (this is somewhat contrived, but I have reasons for wanting to curry this)
    mockSender.Setup(s => s.Send(SendMatchFromCurriedMethod()())).Returns(expected);

    Assert.That(mockSender.Object.Send(expected), Is.EqualTo(expected));
}

public static int SendMatchFromMethod()
{
    return It.IsAny<int>();
}

public static Func<int> SendMatchFromCurriedMethod()
{
    return () => It.IsAny<int>();
}

Редактировать: я знаю о Mock.Of <..> (..) и обычно предпочитаю использовать его, но в данном случае это не таквариант.

Ответы [ 2 ]

6 голосов
/ 03 ноября 2011

Проблема связана с тем, как Moq пытается проанализировать предоставленное дерево выражений для создания сопоставления параметров.Вы можете найти источник здесь: -

http://code.google.com/p/moq/source/browse/trunk/Source/MatcherFactory.cs

Ссылаясь на источник: -

  • It.IsAny<int> совпадения обнаруживаются путем компиляции и выполнения выражениякоторый передается в качестве параметра и ищет любые совпадения (см. здесь ).
  • Вышеуказанный шаг выполняется только для вызовов методов и доступа к элементам

Такс учетом этого ....

  1. Второй тест не пройден, так как метод It.IsAny<int> был оценен за пределами фабрики соответствия.Таким образом, выражение MemberAccess равно 0.
  2. Третий тест пройден, поскольку SendMatchFromMethod рассматривается как выражение вызова метода, а вызов оценивается внутри MatcherFactory.
  3. Четвертый тест завершается неудачно дляПо той же причине, что и вторая, функция уже вычислена, и Moq не может обнаружить, что вы на самом деле вызвали It.Is<Any>
  4. Пятый тест не пройден, поскольку выражение обрабатывается как вызов функции, а Moq не выполняет сопоставление.проверьте этот тип выражения.

Четвертый тест, если честно, должен пройти, и это просто кажется упущением, что оно было прекращено, вероятно, только потому, что это немного крайний случай.

Наконец, Match.Create<T> или MatchAttribute могут использоваться для работы со сложными предикатами, возможно, они могут соответствовать вашему варианту использования?

3 голосов
/ 28 октября 2011

Это, похоже, очень похоже на ситуацию, с которой я столкнулся некоторое время назад: Модульный тест Moq с It.IsAny () завершается неудачей

Проблема, похоже, связана скогда It.IsAny<int>() оценивается.После двух пройденных тестов он оценивается внутри Setup(...), что прекрасно работает.В первых двух неудачных тестах он оценивается за пределами Setup(...), поэтому он не может быть правильно оценен.Вероятно, в вашей переменной хранится результат It.IsAny<int>(), который будет значением по умолчанию для int (0).

Я не знаю точной причины, по которой последний тестможет произойти сбой, но может случиться так, что в качестве оптимизации ваша статическая Func<int> будет оценена до выполнения Setup(...), или может быть, что она будет оценена после Setup(...), но в любом случае это происходит за пределами Setup(...).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...