Moq Verify без него - что за сравнение?

При использовании Moq с Verify, чтобы утверждать, что определенный метод был вызван с указанными параметрами, возможен другой вид синтаксиса; один синтаксис "это", как это

mock.Verify(c => c.SomeMethod(It.Is<string>(s => s == ExpectedString)));

Здесь происходит то, что параметр, который SomeMethod вызывается с, проверяется на равенство с ExpectedString, Другой возможный синтаксис без "Это":

mock.Verify(c => c.SomeMethod(ExpectedString));

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

Тем не менее, мой вопрос, когда параметр имеет тип коллекции типа. В.NET, Equals на Collection<T> просто наследуется от object, так что проверьте следующее:

mock.Verify(c => c.SomeMethod(new Collection<string> { ExpectedString }));

не должно быть возможно передать, учитывая, что экземпляр создан в верификации, и, следовательно, не может быть тот же экземпляр, который создается в производственном коде. Тем не менее, это работает, что указывает на то, что Moq выполняет CollectionAssert или что-то в этом роде, в отличие от той информации, которую я мог найти.

Вот пример кода, который иллюстрирует поведение, тест проходит успешно, но я думаю, что он потерпит неудачу, если Moq использовал сравнение ссылок и сравнений.

[TestMethod]
public void Test()
{
    var mock = new Mock<IPrint>();
    const int ExpectedParam = 1;
    var test = new TestPrinter { Printer = mock.Object, Expected = ExpectedParam };

    test.Do();

    mock.Verify(c => c.Print(new Collection<int> { ExpectedParam }));
}

public interface IPrint
{
    void Print(Collection<int> numbers);
}

public class TestPrinter
{
    public IPrint Printer { get; set; }

    public int Expected { get; set; }

    public void Do()
    {
        Printer.Print(new Collection<int> { Expected });
    }
}

Кто-нибудь знает, ожидается ли это поведение Moq (версия 4.1)? Было ли изменено поведение на каком-то уровне версии?

1 ответ

Решение

Это желаемое поведение, и оно было добавлено в moq в январе 2009 года (версия 3.0.203.1).

Если moq находит IEnumerable, оно использует SequenceEqual сравнить фактический аргумент и аргумент, используемый в настройке, в противном случае он просто использует Equals,

Вот соответствующий фрагмент кода:

internal class ConstantMatcher : IMatcher
{
    ...

    public bool Matches(object value)
    {
        if (object.Equals(constantValue, value))
        {
            return true;
        }

        if (this.constantValue is IEnumerable && value is IEnumerable)
        {
            return this.MatchesEnumerable(value);
        }

        return false;
    }

    private bool MatchesEnumerable(object value)
    {
        var constValues = (IEnumerable)constantValue;
        var values = (IEnumerable)value;
        return constValues.Cast<object>().SequenceEqual(values.Cast<object>());
    }
}
Другие вопросы по тегам