Проверка Moq без него — какое сравнение?

#c# #moq #verify

#c# #moq #проверка

Вопрос:

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

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

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

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

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

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

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

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

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

 [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 находит an IEnumerable , он использует SequenceEqual для сравнения фактический аргумент и аргумент, используемый в настройке, в противном случае он просто использует Equals .

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

 internal class ConstantMatcher : IMatcher
{
    ...

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

        if (this.constantValue is IEnumerable amp;amp; 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>());
    }
}