65 votes

Comment vérifier si une liste est ordonnée ?

Je suis en train de faire des tests unitaires et je veux savoir s'il y a un moyen de tester si une liste est ordonnée par une propriété des objets qu'elle contient.

Pour l'instant, je le fais de cette façon mais je n'aime pas ça, je veux une meilleure méthode. Quelqu'un peut-il m'aider ?

// (fill the list)
List<StudyFeedItem> studyFeeds = 
    Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);   

StudyFeedItem previous = studyFeeds.First();

foreach (StudyFeedItem item in studyFeeds)
{
    if (item != previous)
    {
        Assert.IsTrue(previous.Date > item.Date);
    }

    previous = item;
}

4 votes

Faites attention à ne pas tester des choses qui n'ont pas besoin d'être testées. Vous assurez-vous que la requête contient la clause order by attendue, ou vérifiez-vous simplement que la clause order by fonctionne ? Dans ce dernier cas, c'est du gaspillage.

0 votes

@Chris - c'est un bon point (+1), et je me suis demandé la même chose lorsque j'ai posé la question. Pourquoi dites-vous que tester l'ordre par est une perte de temps ? Devrais-je alors simplement faire confiance au moteur de base de données et au CLR pour que les choses soient claires ?

3 votes

@PITADev : Oui, vous devez absolument faire confiance au moteur de base de données et au CLR pour garder les choses en ordre. Vous ne testez pas que int x = 2, y = 2, z = x + y a Assert.IsTrue(z == 4)' réussir êtes-vous ? Vous devez tester en unité le comportement de vos méthodes publiques et rien de plus. Donc si le comportement attendu de repository.GetItems(true) retourne une liste ordonnée d'éléments, alors testez-la. Mais ne testez pas que items.OrderBy(x => x, new YourComparer()) permet en effet de trier la liste. Cependant, faites le test unitaire que YourComparer se compare en effet correctement.

70voto

Mark Seemann Points 102767

Si vous utilisez MSTest, vous pouvez jeter un coup d'oeil à CollectionAssert.AreEqual .

Enumerable.SequenceEqual peut être une autre API utile à utiliser dans une assertion.

Dans les deux cas, vous devez préparer une liste qui contient la liste attendue dans l'ordre attendu, puis comparer cette liste au résultat.

Voici un exemple :

var studyFeeds = Feeds.GetStudyFeeds(2120, DateTime.Today.AddDays(-200), 20);   
var expectedList = studyFeeds.OrderByDescending(x => x.Date);
Assert.IsTrue(expectedList.SequenceEqual(studyFeeds));

1 votes

La question était : "Existe-t-il un moyen de tester si une liste est ordonnée par une propriété des objets qu'elle contient ?", Donc : un test qui retourne vrai si la séquence est ordonnée par une propriété donnée. PAS : si la séquence est égale à une autre séquence. J'opterais pour une méthode d'extension, en utilisant éventuellement Enumerable.Aggregate

52voto

Greg Beech Points 55270

Une solution .NET 4.0 consisterait à utiliser la fonction Enumerable.Zip pour fermer la liste en la décalant d'une unité, ce qui permet de coupler chaque élément avec l'élément suivant de la liste. Vous pouvez ensuite vérifier que la condition est vraie pour chaque paire, par ex.

var ordered = studyFeeds.Zip(studyFeeds.Skip(1), (a, b) => new { a, b })
                        .All(p => p.a.Date < p.b.Date);

Si vous êtes sur une version antérieure du framework, vous pouvez écrire votre propre méthode Zip sans trop de problème, quelque chose comme ce qui suit (la validation des arguments et l'élimination des énumérateurs si applicable est laissée au lecteur) :

public static IEnumerable<TResult> Zip<TFirst, TSecond, TResult>(
    this IEnumerable<TFirst> first,
    IEnumerable<TSecond> second,
    Func<TFirst, TSecond, TResult> selector)
{
    var e1 = first.GetEnumerator();
    var e2 = second.GetEnumerator();
    while (e1.MoveNext() & e2.MoveNext()) // one & is important
        yield return selector(e1.Current, e2.Current);
}

2 votes

Cela sera plus efficace en termes de mémoire que les autres réponses qui utilisent OrderBy().

2 votes

Il faut que ce soit en haut.

0 votes

Il est possible de simplifier encore davantage la situation en utilisant une seule expression lambda au lieu de deux et en se débarrassant du type anonyme, ce qui améliore la lisibilité. Voir ma réponse . :)

32voto

mattk Points 550

Introduction de Nunit 2.5 CollectionOrderedContraint et une belle syntaxe pour vérifier l'ordre d'une collection :

Assert.That(collection, Is.Ordered.By("PropertyName"));

Plus besoin de commander et de comparer manuellement.

0 votes

J'aime bien ce système, mais dans son état actuel, il est très limité (on ne peut pas ordonner par plusieurs colonnes tout en définissant l'ordre croissant ou décroissant).

0 votes

La fonctionnalité de Nunit a été étendue. Les assertions permettent maintenant l'utilisation de vos propres comparateurs, comme vous pouvez le voir dans le manuel . Les contraintes prennent en charge un certain nombre de paramètres, notamment la direction et le choix de la propriété souhaitée (plusieurs propriétés même).

27voto

Jørn Schou-Rode Points 19947

Si votre cadre de test unitaire dispose de méthodes d'aide pour affirmer l'égalité des collections, vous devriez pouvoir faire quelque chose comme ceci (à la manière de NUnit) :

var sorted = studyFeeds.OrderBy(s => s.Date);
CollectionAssert.AreEqual(sorted.ToList(), studyFeeds.ToList());

La méthode assert fonctionne avec n'importe quel IEnumerable mais lorsque les deux collections sont de type IList ou "array of something", le message d'erreur envoyé en cas d'échec de l'assert contiendra l'index du premier élément non placé.

0 votes

+1. Sympa. J'utilise NUnit depuis des années et je ne connaissais pas cela. Je viens également de découvrir FileAssert et StringAssert ! Merci.

0 votes

Cela ne fonctionne pas :(. Message d'erreur : Baischana.Components.Services.Test.StudyFeedsTest.GetStudyFeeds_IsOrderedByDate : Attendu : <System.Linq.OrderedEnumerable`2[Baischana.Components.StudyFeedItem,System.DateTime]> Mais était : <Baischana.Components.StudyFeedItem>, <Baischana.Components.StudyFeedItem>, <Baischana.Components.StudyFeedItem>, <Baischana.Components.StudyFeedItem>, <Baischana.Components.StudyFeedItem>, <Baischana.Components.StudyFeedItem> >.

1 votes

Le tri d'une liste est assez inefficace en termes de complexité de calcul.

7voto

Jason Points 125291

Pourquoi pas :

var list = items.ToList();
for(int i = 1; i < list.Count; i++) {
    Assert.IsTrue(yourComparer.Compare(list[i - 1], list[i]) <= 0);
} 

yourComparer est une instance de YourComparer qui met en œuvre IComparer<YourBusinessObject> . Cela garantit que chaque élément est inférieur à l'élément suivant dans l'énumération.

0 votes

FYI : fusionné à partir de stackoverflow.com/questions/1676178/

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