Assert.AreEqual не использует переопределения .Equals в реализации IEnumerable
У меня есть класс PagedModel, который реализует IEnumerable, чтобы просто вернуть ModelData, игнорируя данные подкачки. Я также переопределил Equals и GetHashCode, чтобы сравнить два объекта PagedModel по их параметрам ModelData, PageNumber и TotalPages и PageSize.
Здесь проблема
Dim p1 As New PagedModel() With {
.PageNumber = 1,
.PageSize = 10,
.TotalPages = 10,
.ModelData = GetModelData()
}
Dim p2 As New PagedModel() With {
.PageNumber = 1,
.PageSize = 10,
.TotalPages = 10,
.ModelData = GetModelData()
}
p1.Equals(p2) =====> True
Assert.AreEqual(p1, p2) ======> False!
Похоже, что NUnit называет его внутренним методом EnumerableEqual для сравнения моего PagedModel вместо использования методов Equals, которые я предоставил! Есть ли способ переопределить это поведение или мне нужно написать настраиваемое утверждение.
Ответы
Ответ 1
Выполнение того, что вы просите. Я бы посоветовал это, но если вам действительно не нравится поведение NUnit и вы хотите настроить утверждение, вы можете предоставить свой собственный EqualityComparer.
Assert.That(p1, Is.EqualTo(p2).Using(myCustomEqualityComparer));
Что вы должны делать (короткий ответ): вам нужен GetHashCode и равен ModelData вместо PagedModel, поскольку вы используете PagedModel в качестве коллекции и ModelData как элементы.
Что вы должны делать (длинный ответ):
Вместо переопределения Equals (object) на PagedModel вам нужно реализовать IEquatable <T> в ModelData, где T является параметром типа для IEnumerable, а также переопределяет GetHashCode(). Эти два метода - это то, что все методы IEnumerable в .Net используют для определения равенства (для операций, таких как Union, Distinct и т.д.) При использовании Default Equality Comparer (вы не указываете свой собственный IEqualityComparer).
[Default Equality Comparer] проверяет, реализует ли тип T интерфейс System.IEquatable, и, если это так, возвращает EqualityComparer, который использует эту реализацию. В противном случае он возвращает EqualityComparer, который использует переопределения Object.Equals и Object.GetHashCode, предоставленные T.
Чтобы правильно функционировать, GetHashCode должен возвращать те же результаты для всех объектов, которые возвращают true для .Equals(T). Обратное не обязательно верно - GetHashCode может возвращать столкновения для объектов, которые не равны. Дополнительная информация здесь - см. ответ Марка Гравеля. Я также нашел реализацию GetHashCode в этом ответе, используя простые значения.
Ответ 2
Если вы посмотрите на реализацию сопоставления равенства NUnit в GIT repo, вы увидите, что есть выделенный блок сравнения для двух перечислений, который имеет более высокий приоритет (просто потому, что он помещен выше), чем сравнения с использованием интерфейса IEquatable<T>
или Object.Equals(Object)
, который вы внедрили или перегрузили в своем классе PagedModel
.
Я не знаю, является ли это ошибкой или функцией, но вы, вероятно, должны сначала спросить себя, если реализация интерфейса IEnumerable<ModelData>
непосредственно вашим классом PagedModel
на самом деле является лучшим вариантом, особенно потому, что ваш PagedModel
это нечто большее, чем просто перечисление экземпляров ModelData
.
Вероятно, было бы достаточно (или даже лучше) предоставить перечисление ModelData
через простое свойство IEnumerable<ModelData>
только для чтения класса PagedModel
. NUnit перестанет смотреть на ваш объект PagedModel
, как при простой перечислении объектов ModelData
, и ваши модульные тесты будут вести себя так, как ожидалось.
Единственный другой вариант - это предложение, предлагаемое csauve; для реализации простой пользовательской IComparer
для вашего PagedModel
и для поставки экземпляра для всех утверждений, где вы сравниваете два экземпляра PagedModel
:
internal class PagedModelComparer : System.Collections.IComparer
{
public static readonly IComparer Instance = new PagedModelComparer();
private PagedModelComparer()
{
}
public int Compare( object x, object y )
{
return x is PagedModel && ((PagedModel)x).Equals( y );
}
}
...
[Test]
...
Assert.That( actual, Is.EqualTo( expected ).Using( PagedModelComparer.Instance ) );
...
Но это сделает ваши тесты более сложными, чем необходимо, и вам всегда придется думать, чтобы использовать ваш специальный компаратор всякий раз, когда вы пишете дополнительные тесты для PagedModel
.