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