web-dev-qa-db-fra.com

NUnit comparant deux listes

OK, je suis donc relativement nouveau dans les tests unitaires et tout se passe bien jusqu'à présent. Je simplifie mon problème ici, mais fondamentalement, j'ai les éléments suivants:

[Test]
public void ListTest()
{
    var expected = new List<MyClass>();
    expected.Add(new MyOtherClass());
    var actual = new List<MyClass>();
    actual.Add(new MyOtherClass());
    Assert.AreEqual(expected,actual);
    //CollectionAssert.AreEqual(expected,actual);
}

Mais le test échoue, le test ne devrait-il pas réussir? Qu'est-ce que je rate?

22
SOfanatic

Je convertis mon commentaire pour y répondre sur demande.

Eh bien, cela échoue car AreEqual utilise la comparaison de référence. Pour que cela fonctionne, vous avez besoin d'une comparaison de valeur (votre propre comparaison personnalisée).

Vous pouvez à peu près le faire en implémentant l'interface IEquatable . et gardez à l'esprit lorsque vous implémentez cette interface, vous devez remplacer Object.Equals et Object.GetHashCode également pour obtenir des résultats cohérents.

Le framework .Net prend en charge cela sans implémenter IEquatable dont vous avez besoin IEqualityComparer qui devrait faire l'affaire, mais nunit devrait avoir une méthode qui prend cela comme une surcharge. Je ne suis pas certain cependant de "nunit".

7
Sriram Sakthivel

Si vous comparez deux listes, vous devez utiliser test en utilisant contraintes de collecte .

Assert.That(actual, Is.EquivalentTo(expected));

De plus, dans vos classes, vous devrez remplacer la méthode Equals, sinon, comme l'a déclaré gleng, les éléments de la liste seront toujours comparés en fonction de la référence.

Exemple de remplacement simple:

public class Example
{
    public int ID { get; set; }

    public override bool Equals(object obj)
    {
        return this.ID == (obj as Example).ID;
    }
}
42
matth

Un moyen très simple de faire fonctionner ce test consiste à ne créer l'instance MyOtherClass qu'une seule fois. De cette façon, lors de la comparaison de l'élément dans les deux listes, ils seront "égaux" (car ils font référence au même objet). Si vous faites cela, CollectionAssert fonctionnera très bien.

[Test]
public void ListTest()
{
    var thing = new MyOtherClass();

    var expected = new List<MyClass>();
    expected.Add(thing);

    var actual = new List<MyClass>();
    actual.Add(thing);

    CollectionAssert.AreEqual(expected,actual);
}

Si vous ne le faites pas, vous devrez implémenter IEquatable<MyOtherClass> dans MyOtherClass ou remplacer Equals pour définir ce qui fait que deux instances de cette classe sont "identiques".

10
Jeff B

Essayez d'être un peu plus précis sur ce que vous essayez de réaliser. Dire explicitement que vous voulez comparer la séquence entière résoudra le problème. Personnellement, je ne me fierais pas aux fonctionnalités sophistiquées de NUnit pour déterminer ce que vous vouliez dire par AreEqual. Par exemple.

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

De Nunit documentation :

À partir de la version 2.2, une disposition spéciale est également prévue pour comparer les tableaux unidimensionnels. Deux tableaux seront traités comme égaux par Assert.AreEqual s'ils sont de la même longueur et que chacun des éléments correspondants est égal. Remarque: les tableaux multidimensionnels, les tableaux imbriqués (tableaux de tableaux) et d'autres types de collection tels que ArrayList ne sont actuellement pas pris en charge.

Vous avez une liste d'objets ... ce n'est donc pas la même chose que de comparer 2 pouces. Ce que vous devez faire est probablement de comparer tous les objets à l'intérieur de la liste ... (Essayez de convertir votre liste en un tableau ... cela pourrait en fait fonctionner :))


Comme je l'ai dit (et la plupart des autres également), vous devrez probablement remplacer Equals. Voici MSDN page sur la façon de le faire (couvre égal, opérateur == et GetHashCode).

Similaire avec plus d'informations: [compare-égalité-entre-deux-objets-dans-nunit]
( Comparer l'égalité entre deux objets dans NUnit )

2
Noctis

Si vous ne pouvez pas modifier une classe, cet exemple peut être utile:

[Test]
public void Arrays_Should_Be_Equal()
{
    MyClass[] array1 = GetTestArrayOfSize(10);
    MyClass[] array2 = GetTestArrayOfSize(10);

    // DOESN'T PASS
    // Assert.That(array1, Is.EquivalentTo(array2));

    Func<MyClass, object> selector = i => new { i.Property1, i.Property2 };
    Assert.That(array1.Select(selector), Is.EquivalentTo(array2.Select(selector)));
}

private MyClass[] GetTestArrayOfSize(int count)
{
    return Enumerable.Range(1, count)
        .Select(i => new MyClass { Property1 = "Property1" + i, Property2 = "Property2" + i }).ToArray();
}
1