36 Stimmen

Wie wird mit Assert.AreEqual die Gleichheit zwischen zwei generischen IEnumerables festgestellt?

Ich habe einen Unit-Test, um zu prüfen, ob eine Methode die richtige IEnumerable . Die Methode baut die Aufzählung auf, indem sie yield return . Die Klasse, von der es ein Enumerable ist, steht unten:

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 der Methode:

 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 eine weitere aufzählbare expected und vergleichen Sie sie so...

  Assert.AreEqual(expected, actual);

..., scheitert die Behauptung.

Ich habe eine Erweiterungsmethode für IEnumerable die ähnlich ist wie Pythons zip Funktion (es kombiniert zwei IEnumerables in eine Reihe von Paaren) und versuchte dies:

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

Es hat geklappt! Was ist also der Unterschied zwischen diesen beiden Assert.AreEqual s?

90voto

Jason Baker Punkte 180981

Ich habe es gefunden:

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

49voto

jerryjvl Punkte 18807

Haben Sie in Erwägung gezogen, die CollectionAssert Klasse stattdessen... wenn man bedenkt, dass sie dazu gedacht ist, Gleichheitsprüfungen für Sammlungen durchzuführen?

Nachtrag:
Handelt es sich bei den zu vergleichenden "Sammlungen" um Aufzählungen, so werden diese einfach mit ' new List<T>(enumeration) ' ist der einfachste Weg, den Vergleich durchzuführen. Der Aufbau einer neuen Liste verursacht natürlich einen gewissen Overhead, aber im Rahmen eines Einheitstests sollte dies nicht allzu sehr ins Gewicht fallen, hoffe ich.

25voto

jrista Punkte 31522

Assert.AreEqual wird die beiden vorliegenden Objekte vergleichen. IEnumerable s sind Typen an und für sich und bieten einen Mechanismus, um über eine Sammlung zu iterieren... aber sie sind nicht wirklich diese Sammlung. Ihr ursprünglicher Vergleich verglich zwei IEnumerable s, was ein gültiger Vergleich ist... aber nicht das, was Sie brauchten. Sie mussten vergleichen was die beiden IEnumerable s sollten aufgezählt werden .

So vergleiche ich zwei Aufzählungszeichen:

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 mir nicht sicher, ob das oben genannte weniger Code ist als Ihr .Zip Methode, aber sie ist so einfach wie nur möglich.

21voto

bacar Punkte 9371

Ich denke, der einfachste und klarste Weg, um die gewünschte Gleichheit zu erreichen, ist eine Kombination aus der Antwort von jerryjvl und dem Kommentar zu seinem Beitrag von MEMark - kombinieren CollectionAssert.AreEqual mit Erweiterungsmethoden:

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

Dies liefert umfangreichere Fehlerinformationen als die vom Auftraggeber vorgeschlagene SequenceEqual-Antwort (sie gibt an, 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 froh, dass Sie es so gemacht haben, wenn Ihr Test fehlschlägt - manchmal können Sie sogar wissen, was falsch ist, ohne den Debugger herauszuholen - und hey, Sie machen TDD richtig, also schreiben Sie zuerst einen fehlschlagenden Test, richtig? ;-)

Die Fehlermeldungen werden noch hilfreicher, wenn Sie Folgendes verwenden AreEquivalent um die Gleichwertigkeit zu prüfen (die 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).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X