简体   繁体   中英

How to test if two collections of objects are in a different order based on one of the objects' properties?

I'm reasonably new to unit testing and I'm running into a problem. I have two collections (decks) holding objects (cards), with the cards being objects that have an ID, value, suit etc.

I'm writing a unit test to see if my Shuffle() method works, so I want to test if an unshuffled deck (which creates 52 cards with IDs 0-51) and a shuffled deck are in the same order or not. Obviously, the cards are unique objects, even if they hold the same values. So by definition, testing to see if they're the same will always result in false. I'm very, very new to NUnit (just installed it two days ago) and I'm still struggling with the syntax here and there.

Ideally, I'd want an assertion to check if the order of both collections is the same, with the order being determined by the cards' IDs because, as objects, they are all unique and therefore always in a different order. Now, I can check if the shuffled deck is no longer ordered by ID, but that would be a bad unit test since it assumes that an unshuffled deck is always ordered by ID. I can also check the unshuffled deck, but it seems rather inelegant to test it that way without actually comparing the two decks.

I also want an assertion to check that my deck constructor creates only unique IDs, but again, all objects in the collection are always unique but I don't know the syntax (if it exists) for checking for uniqueness of one specific property of all the cards.

I've been Googling like crazy, and I've been trying a lot of different syntax things by brute force, but I'm at a loss now. I hope you guys can help me, thanks in advance!

You can use SequnceEqual with LINQ Select like that:

class Card
{
    public int CardId { get; set; }
}

Assert.IsTrue(new[] { new Card {CardId = 1}, new Card {CardId = 2}}
        .Select(c => c.CardId)
        .SequenceEqual(new[] {1,2}));

Also I would recommend to check out Fluent Assertions library, sometimes it is not very obvious how to do things there but in general it has some very useful features.

To determine if the cards are in the same order by using the Id property, you can simply select that property into an IEnumerable and then use the System.Linq extension method SequenceEqual on them:

// Where 'unshuffled' and 'shuffled' are both 'List<Card>' objects
var areEqual = unshuffled.Select(c => c.Id).SequenceEqual(shuffled.Select(c => c.Id));

Alternatively, you could overried Equals and GetHashCode on the Card class, and then use that for the equality comparison. This will help with other card comparisons that may be needed:

public class Card : IEquatable<Card>
{
    public int Id { get; set; }

    public bool Equals(Card other)
    {
        return Id == other?.Id;
    }

    public override bool Equals(object obj)
    {
        return Equals(obj as Card);
    }

    public override int GetHashCode()
    {
        return Id;
    }
}

Now our comparison code is slightly more simple:

var areEqual = unshuffled.SequenceEqual(shuffled);

Simplest approach for your case using NUnit features only is

Assert.That(shuffled, Is.Not.EqualTo(unshuffled);

Note that this assumes you have overridden Equals for the card object.

Why this works...

  1. Your decks all have 52 cards
  2. You are also testing (I assume this) that each deck contains the right 52 cards.
  3. NUnit Equality over collections is defined as each pair of elements, taken in order, being equal.

For a full set of tests, I'd probably want to make sure that the deck size didn't change and that all elements were unique. Something like...

Assert.That(shuffled, Is.EqualTo(DECK_SIZE);
Assert.That(shuffled, Is.Unique);
Assert.That(shuffled, Is.Not.EqualTo(unshuffled));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM