2009-06-01 13 views
35

Ich habe einen Komponententest, um zu überprüfen, ob eine Methode die richtige IEnumerable zurückgibt. Die Methode erstellt das Enumerable mit yield return. Die Klasse, die es ist eine zählbare von unter:Wie bestimmt Assert.AreEqual die Gleichheit zwischen zwei generischen IEnumerables?

enum TokenType 
{ 
    NUMBER, 
    COMMAND, 
    ARITHMETIC, 
} 

internal class Token 
{ 
    public TokenType type { get; set; } 
    public string text { get; set; } 
    public static bool operator == (Token lh, Token rh) { return (lh.type == rh.type) && (lh.text == rh.text); } 
    public static bool operator != (Token lh, Token rh) { return !(lh == rh); } 
    public override int GetHashCode() 
    { 
     return text.GetHashCode() % type.GetHashCode(); 
    } 
    public override bool Equals(object obj) 
    { 
     return this == (Token)obj; 
    } 
} 

Dies ist der relevante Teil des Verfahrens:

foreach (var lookup in REGEX_MAPPING) 
{ 
    if (lookup.re.IsMatch(s)) 
    { 
     yield return new Token { type = lookup.type, text = s }; 
     break; 
    } 
} 

Wenn ich das Ergebnis dieser Methode in actual speichern, eine andere zählbare expected machen, und vergleiche sie so ...

Assert.AreEqual(expected, actual); 

..., die Assertion schlägt fehl.

Ich schrieb eine Erweiterungsmethode für IEnumerable, die zu Python's zip function ähnlich ist (es verbindet zwei IEnumerables in eine Menge von Paaren) und versucht, dies:

foreach(Token[] t in expected.zip(actual)) 
{ 
    Assert.AreEqual(t[0], t[1]); 
} 

Es hat funktioniert! Also, was ist der Unterschied zwischen diesen beiden Assert.AreEqual s?

+1

@ Jason Baker: bitte das der falsche nicht nehmen Sie Hast du gedacht, dass die Tatsache, dass du eine Frage wie diese stellen musst, bedeuten könnte, dass du die Dinge zu kompliziert machst? –

+1

Ähm ... Nein, nicht wirklich. : Könntest du mich auf etwas hinweisen, wo ich die Dinge kompliziert mache? –

+0

Ich bin auch nicht davon überzeugt, dass "text.GetHashCode()% type.GetHashCode();" als Rückgabewert für GetHashCode() ist eine gute Idee ... –

Antwort

25

Assert.AreEqual wird die beiden Objekte in der Hand vergleichen. IEnumerable s sind Typen an und für sich, und bieten einen Mechanismus, um über einige Sammlung zu iterieren ... aber sie sind nicht wirklich diese Sammlung. Dein ursprünglicher Vergleich vergleicht zwei IEnumerable s, was ein valider Vergleich ist ... aber nicht was du brauchst. Sie mussten vergleichen, was die beiden IEnumerable s waren, um aufzuzählen.

Hier ist, wie ich vergleichen zwei enumerables:

Assert.AreEqual(t1.Count(), t2.Count()); 

IEnumerator<Token> e1 = t1.GetEnumerator(); 
IEnumerator<Token> e2 = t2.GetEnumerator(); 

while (e1.MoveNext() && e2.MoveNext()) 
{ 
    Assert.AreEqual(e1.Current, e2.Current); 
} 

Ich bin nicht sicher, ob die obige ist weniger Code als Ihre .Zip Methode, aber es ist ungefähr so ​​einfach wie es nur geht.

+0

Das macht Sinn. Gibt es keine Möglichkeit, die beiden IEnumerables Objekt für Objekt zu vergleichen, ohne so viel Code schreiben zu müssen wie nötig? –

+0

Ich würde nur eine while-Schleife verwenden. Ich habe meine Antwort mit einem Beispiel aktualisiert. – jrista

+0

Ich habe einen anderen Weg gefunden, der funktioniert und einfacher ist. Ich akzeptiere das, seit du gezeigt hast, warum mein Code nicht funktioniert hat. :-) –

86

es gefunden:

Assert.IsTrue(expected.SequenceEqual(actual)); 
+0

Nice find! Ich wusste nicht einmal, dass es eine SequenceEqual() Erweiterung gibt. Ty! – jrista

+0

Vielen Dank. Sie haben meine Loops gespeichert ;-) –

+3

Dies wird Ihnen keine Informationen darüber geben, welches Element bei fehlgeschlagenem Test ungleich war. es wird dir nur sagen, dass es fehlgeschlagen ist. Der von jerryjvl vorgeschlagene CollectionAssert-Mechanismus liefert viel reichhaltigere Fehlerinformationen. – bacar

47

Haben Sie darüber nachgedacht, anstatt die CollectionAssert-Klasse ... man bedenkt, dass es auf Sammlungen Gleichheit Kontrollen durchführen soll?

Nachtrag:
Wenn die ‚Sammlungen‘ Aufzählungen sind verglichen wird, dann einfach mit ‚new List<T>(enumeration)‘ Verpackung ist der einfachste Weg, um den Vergleich durchzuführen. Das Erstellen einer neuen Liste verursacht natürlich einen gewissen Overhead, aber im Rahmen eines Komponententests sollte das nicht so wichtig sein, hoffe ich.

+0

Alle Methoden in CollectionAssert werden jedoch so eingestellt, dass sie mit ICollections verglichen werden. Ich habe IEnumerables. Gibt es eine einfache Möglichkeit, sie in ICollections zu ändern? –

+0

In solchen Fällen mache ich normalerweise nur eine kurze Zusammenfassung in einer 'neuen Liste (Enumeration) ', damit ich den Vergleich durchführen kann. Es ist nicht so, dass der Overhead im Zusammenhang mit einem Komponententest ein Problem darstellt. – jerryjvl

+6

Tun Sie einfach ToArray() für beide Argumente, wenn Sie CollectionAssert verwenden. – MEMark

18

Ich denke, die einfachste und klarste Weg, um die Gleichheit Sie behaupten wollen, ist eine Kombination aus der Antwort von jerryjvl und Kommentar zu seinem Beitrag von MEMark - kombinieren CollectionAssert.AreEqual mit Methoden Erweiterung:

CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray()); 

Dies gibt reichen Fehler Informationen als die vom OP vorgeschlagene SequenceEqual-Antwort (es wird Ihnen sagen, welches Element gefunden wurde, das unerwartet war).Zum Beispiel:

IEnumerable<string> expected = new List<string> { "a", "b" }; 
IEnumerable<string> actual = new List<string> { "a", "c" }; // mismatching second element 

CollectionAssert.AreEqual(expected.ToArray(), actual.ToArray()); 
// Helpful failure message! 
// CollectionAssert.AreEqual failed. (Element at index 1 do not match.)  

Assert.IsTrue(expected.SequenceEqual(actual)); 
// Mediocre failure message: 
// Assert.IsTrue failed. 

Sie werden wirklich erfreute man es auf diese Art und Weise haben, wenn/falls Ihr Test nicht besteht - manchmal kann man auch wissen, was ohne den Debugger auszubrechen falsch ist - und hey, du bist TDD richtig machen, also schreiben Sie zuerst einen versagenden Test, richtig? ;-)

Die Fehlermeldungen noch hilfreich, wenn Sie AreEquivalent verwenden für Gleichwertigkeit zu testen (Reihenfolge spielt keine Rolle):

CollectionAssert.AreEquivalent(expected.ToList(), actual.ToList()); 
// really helpful error message! 
// CollectionAssert.AreEquivalent failed. The expected collection contains 1 
// occurrence(s) of <b>. The actual collection contains 0 occurrence(s). 
Verwandte Themen