2012-05-24 16 views
14

Tengo una clase PagedModel que implementa IEnumerable para que simplemente devuelva el ModelData, ignorando los datos de paginación. También he reemplazado Equals y GetHashCode para permitir comparar dos objetos de PagedModel por sus ModelData, PageNumber, TotalPages y PageSize.Assert.AreEqual no usa mis sustituciones de .Equals en una implementación de IEnumerable

Aquí está el problema

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! 

Parece que NUnit está llamando es EnumerableEqual método interno de comparar en lugar de utilizar los métodos que proporcioné Igual a mi PagedModel! ¿Hay alguna manera de anular este comportamiento o tengo que escribir una declaración personalizada?

Respuesta

9

Haciendo lo que está pidiendo: Aconsejaría en contra, pero si realmente no le gusta el comportamiento de NUnit y desea personalizar la afirmación, puede proporcionar su propio EqualityComparer.

Assert.That(p1, Is.EqualTo(p2).Using(myCustomEqualityComparer)); 

Lo que debe hacer (respuesta corta): Es necesario GetHashCode y es igual en vez de ModelData PagedModel dado que está utilizando PagedModel como la recogida y ModelData como los elementos.

Lo que debe hacer (Respuesta larga): En lugar de anular Equals(object) en PagedModel es necesario implementar IEquatable<T> en ModelData, donde T es el parámetro de tipo a la IEnumerable, así como anulación GetHashCode(). Estos dos métodos son los que utilizan todos los métodos IEnumerable en .Net para determinar la igualdad (para operaciones como Union, Distinct, etc.) cuando se usa Default Equality Comparer (no especifica su propio IEqualityComparer).

El [Default Igualdad Comparer] comprueba si el tipo T implementa la interfaz System.IEquatable y, si es así, devuelve un EqualityComparer que utiliza que la aplicación. De lo contrario, devuelve un EqualityComparer que utiliza las anulaciones de las Object.equals y Object.GetHashCode proporcionadas por T.


Para que funcione correctamente, GetHashCode tiene que devolver los mismos resultados para todos los objetos que devuelven cierto para .equals (T). Lo contrario no es necesariamente cierto: GetHashCode puede devolver colisiones para objetos que no son iguales. More information here - see Marc Gravel's accepted answer. También encontré la implementación de GetHashCode en esa respuesta usando primos muy útiles.

+0

Lo que esta respuesta está diciendo es que esencialmente en su implementación necesita implementar explícitamente IEquatable .Equals ... ver http://stackoverflow.com/questions/1577149/explite-interface-implementation-in-vb-net – Jay

+0

No, implementar IEquatable no es suficiente. La implementación de GetHashCode es igual de importante. También es importante comprender que IEnumerable recurre al uso de Equals (objeto) si no implementa IEquatable (vea la cita en mi publicación), por lo que no es absolutamente necesario. – csauve

+0

Dije explícitamente la implementación de IEquatable.Equals que no debería permitir la recuperación por defecto porque el método sería sobrescrito y la implementación explícita llamaría a dicho método ... – Jay

1

Si usted toma un vistazo a la implementación del comparador de igualdad NUnit en el GIT repo, se verá que hay un bloque de comparación dedicado para dos enumeraciones, que tiene una prioridad más alta (simplemente porque se coloca más alto) que el comparisons utilizando la interfaz IEquatable<T> o el método Object.Equals(Object), que ha implementado o sobrecargado en su clase PagedModel.

No sé si se trata de un error o de una pieza, pero probablemente debería preguntarse en primer lugar, si la implementación de la interfaz IEnumerable<ModelData> directamente por la clase PagedModel es realmente la mejor opción, sobre todo porque su PagedModel es algo más que solo una enumeración de instancias ModelData.

Probablemente sería suficiente (o incluso mejor) para proporcionar la enumeración ModelData través de un sencillo de sólo lectura IEnumerable<ModelData> propiedad de la clase PagedModel. NUnit dejaría de buscar en su objeto PagedModel como en una simple enumeración de objetos ModelData y sus pruebas unitarias se comportarían como se esperaba.

La única otra opción es la sugerida por csauve; para poner en práctica un simple encargo IComparer para su PagedModel y para suministrar una instancia del mismo a todas afirma donde se comparan dos PagedModel casos:

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)); 
    ... 

Pero esto hará que sus pruebas más complicado de lo necesario y que siempre tendrá a piense en usar su comparador especial cada vez que esté escribiendo pruebas adicionales para el PagedModel.

Cuestiones relacionadas