Search code examples
c#.netunit-testingbddfluent-assertions

Comparing collections with different item types


I have two collections with different item types, for example:

var collection1 = new List<Type1>();
var collection2 = new List<Type2>();

Is it possible to assert that two collections with different item types contain equal items in any order using my own equality comparer with the FluentAssertions?

The most related example from the official FA documentation considers that both collections are the same type:

persistedCustomers.Should().Equal(customers, (c1, c2) => c1.Name == c2.Name);

One possible solution to use this approach for my situation is to create a new List<Type1> collection based on items from the collection2 and use it instead of customers in the example above.
But sometimes it's just not possible and actually smells like an overhead.

I'm wondering if there is a similar approach that uses FA elegance like the above one but suitable for the collections with different item types?

UPDATE 1 (trying to use @DennisDoomen suggestion):

Let's take more specific example.
Suppose we have a List<DateTime> of expected values that represents dates of a single month:

    var expectation = new List<DateTime>();

A testing method returns a List<int> of day numbers:

    var actual = new List<int>();

We want to assert that the set of day numbers returned by testing method is the same as a set composed from DateTime.Day values of the expectation list, i.e.:

    Assert.AreEqual(expectation[0].Day, actual[0]);
    Assert.AreEqual(expectation[1].Day, actual[1]);
...
    Assert.AreEqual(expectation[expectation.Count - 1].Day, actual[actual.Count - 1]);

(but without the ordering restriction which I don't how to demonstrate in this example).

I'm trying to use @DennisDoomen suggestion in this way:

    actual.ShouldBeEquivalentTo(
        expectation,
        options => options.Using<int>(
            ctx => ctx.Subject.Should().Be(ctx.Expectation.Day)).WhenTypeIs<int>());

The problem is that ctx.Expectation here is a type of int, not a DateTime, so I can't get DateTime.Day anyhow.

What am I missing here?


Solution

  • ShouldBeEquivalentTo is what you need. By default it will ensure that each collection contains items that are structurally equivalent in any order. You can then use the Using/When options to define how Type1 and Type2 should be compared. Something like:

    collection1.ShouldBeEquivalentTo(collection2, options => options 
       .Using<Type1>(t1 => ctx.Subject.Should().Be(ctx.Expectation) 
       .WhenTypeIs<Type1>();