2012-05-24 4 views
14

ich eine PagedModel Klasse haben, die IEnumerable implementiert, um nur die ModelData zurückkehren, ohne auf die Paging-Daten. Ich habe auch Equals und GetHashCode überschrieben, um den Vergleich von zwei PagedModel-Objekten mit ihren ModelData, PageNumber und TotalPages sowie PageSize zu ermöglichen.Assert.AreEqual nicht meine .Equals Überschreibungen auf einer IEnumerable-Implementierung verwenden

Hier ist das Problem

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! 

Es ist wie NUnit aussieht wird es interne EnumerableEqual Methode ruft meinen PagedModel ist anstelle der Verwendung der Methoden vergleichen Equals I zur Verfügung gestellt! Gibt es eine Möglichkeit, dieses Verhalten zu überschreiben, oder muss ich eine benutzerdefinierte Assertion schreiben?

Antwort

9

Tun Sie, was Sie fragen: Ich würde davon abraten, aber wenn Sie wirklich NUnit Verhalten nicht mögen und die Behauptung anpassen möchten, können Sie Ihre eigenen EqualityComparer bieten.

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

Was sollten Sie (kurze Antwort) tun: Sie müssen GetHashCode und gleich auf ModelData statt PagedModel da Sie PagedModel als die Sammlung und ModelData wie die Elemente verwenden.

Was sollten Sie (Lange Antwort) tun: Statt Equals(object) auf PagedModel vorran müssen Sie IEquatable<T> auf ModelData implementieren, wobei T der Typ-Parameter auf die IEnumerable ist, sowie Überschreibung GetHashCode(). Diese beiden Methoden verwenden alle IEnumerable-Methoden in .Net, um die Gleichheit zu bestimmen (für Vorgänge wie Union, Distinct usw.), wenn Sie die Default Equality Comparer verwenden (Sie geben keine eigene IEqualityComparer an).

Die [Standardgleichheitsvergleichs] überprüft, ob Typ T die System.IEquatable-Schnittstelle implementiert, und wenn ja, ein EqualityComparer zurückgibt, dass die Umsetzung verwendet. Ansonsten kehrt ein EqualityComparer, die die Überschreibungen von Object.Equals und Object.GetHashCode von T.


vorgesehen verwendet korrekt funktioniert, muss GetHashCode die gleichen Ergebnisse für alle Objekte zurückzugeben, die für .Equals true zurück (T). Das Gegenteil ist nicht unbedingt wahr - GetHashCode kann Kollisionen für Objekte zurückgeben, die nicht gleich sind. More information here - see Marc Gravel's accepted answer. Ich habe auch die Implementierung von GetHashCode in dieser Antwort mit Primzahlen sehr nützlich gefunden.

+0

Was diese Antwort sagt ist, dass Sie im Wesentlichen in Ihrer Implementierung IEquatable .Equals implementieren müssen ... siehe http://stackoverflow.com/questions/1577149/explicit-interface-implementation-in-vb-net – Jay

+0

Nein, die Implementierung von IEquatable ist nicht genug. Die GetHashCode-Implementierung ist genauso wichtig. Es ist auch wichtig zu verstehen, dass IEnumerable auf die Verwendung von Equals (Objekt) zurückgreift, wenn IEquatable nicht implementiert wird (siehe das Zitat in meinem Beitrag), also ist dies nicht unbedingt erforderlich. – csauve

+0

Ich sagte explizit IEquatable.Equals zu implementieren, die das Standard-Fallback nicht zulassen sollte, da die Methode überschrieben werden würde und die explizit Implementierung würde diese Methode aufrufen ... – Jay

1

Wenn Sie einen Blick auf die Umsetzung der Gleichstellung NUnit nehmen comparer im GIT repo, werden Sie sehen, dass es eine spezielle Vergleichsblock für zwei Aufzählungen, die eine höhere Priorität hat (einfach, weil es höher platziert) als die comparisons unter Verwendung der IEquatable<T> Schnittstelle oder der Object.Equals(Object) Methode, die Sie in Ihrer PagedModel Klasse implementiert oder überlastet haben.

Ich weiß nicht, ob dies ein Fehler ist oder ein Feature, aber man sollte sich wahrscheinlich zuerst fragen, ob die IEnumerable<ModelData> Schnittstelle direkt von Ihrem PagedModel Klasse Implementierung ist eigentlich die beste Option, vor allem, weil Ihr PagedModel ist etwas mehr als nur eine Aufzählung von ModelData Instanzen.

Wahrscheinlich wäre es genug (oder sogar besser), die ModelData Aufzählung über eine einfache Nur-Lese-IEnumerable<ModelData> Eigenschaft der PagedModel Klasse bereitzustellen. NUnit würde aufhören, Ihr PagedModel-Objekt wie bei einer einfachen Enumeration von ModelData Objekte zu betrachten, und Ihre Komponententests würden sich wie erwartet verhalten.

Die einzige andere Option ist die von csauve vorgeschlagen; eine einfache benutzerdefinierte IComparer für Ihre PagedModel zu implementieren und eine Instanz davon an alle liefern behauptet, wo Sie zwei PagedModel Instanzen vergleicht:

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

Aber dies wird Ihre Tests komplizierter als nötig machen und Sie müssen immer Denken Sie daran, Ihren speziellen Vergleich zu verwenden, wenn Sie zusätzliche Tests für die PagedModel schreiben.

Verwandte Themen