35 votes

Comment Assert.AreEqual détermine-t-il l'égalité entre deux IEnumerables génériques?

J'ai une unité de test qui permettra de tester pour voir si une méthode qui retourne le bon IEnumerable. La méthode s'appuie à l'aide de l'interface IEnumerable yield return. La classe qu'il est un IEnumerable de est ci-dessous:

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; }
}

C'est la partie pertinente de la méthode:

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

Si je stocker le résultat de cette méthode en actual et de faire un autre énumérable expected et de les comparer comme ceci:

  Assert.AreEqual(expected, actual);

...l'assertion échoue.

J'ai écrit une méthode d'extension pour IEnumerable qui est similaire à Python zip fonction (il combine deux IEnumerables dans un ensemble de paires), et j'ai essayé ceci:

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

...et cela a fonctionné! Quelle est donc la différence entre ces deux Assert.AreEquals?

88voto

Jason Baker Points 56682

Je l'ai trouvé:

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

48voto

jerryjvl Points 9310

Avez-vous envisagé d'utiliser la classe CollectionAssert la place ... étant donné qu'elle est destinée à effectuer des vérifications d'égalité sur les collections?

Addenda:
Si les `` collections '' comparées sont des énumérations, le simple encapsulation dans `` new List<T>(enumeration) '' est le moyen le plus simple d'effectuer la comparaison. La construction d'une nouvelle liste entraîne des frais généraux, mais dans le contexte d'un test unitaire, cela ne devrait pas trop d'importance, j'espère?

25voto

jrista Points 20950

Affirmer.AreEqual va comparer les deux objets à portée de main. IEnumerables sont des types dans et d'eux-mêmes, et de fournir un mécanisme pour effectuer une itération sur certains de la collection...mais ils ne sont pas réellement cette collection. L'original de votre comparaison par rapport à deux IEnumerables, qui est une comparaison valable...mais ce n'était pas ce dont vous avez besoin. Vous avez besoin de comparer ce que les deux IEnumerables étaient destinés à énumérer.

Voici comment je compare deux 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);
}

Je ne suis pas sûr si le ci-dessus est à moins de code que ce que votre .Zip méthode ou pas, mais ses propos aussi simple que cela.

19voto

bacar Points 2017

Je pense que le plus simple et le plus clairement possible d'affirmer l'égalité que vous voulez est une combinaison de la réponse par jerryjvl et des commentaires sur son post par MEMark - combiner CollectionAssert.AreEqual avec les méthodes d'extension:

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

Cela donne des informations plus complètes que les SequenceEqual réponse suggérée par les OP (il vous dira à quel élément a été trouvé que c'était inattendu). Par exemple:

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.   

Vous serez vraiment heureux que vous avez fait cela de cette façon, si/lorsque votre test échoue - parfois, vous pouvez même savoir quel est le problème sans avoir à sortir le débogueur - et hey, vous êtes en train de faire TDD droit, de sorte que vous écrivez un test en échec en premier, d'accord? ;-)

Les messages d'erreur d'obtenir encore plus utile si vous utilisez AreEquivalent pour tester l'équivalence (l'ordre n'a pas d'importance):

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X