Search code examples
c#testingfluent-assertions

FluentAssertions: Test if an Enumerable contains "subset" of itself


I'm looking for the elegant expression to test if an enumerable contains a 'subset' of itself.

Lets me illustrate with a sample:

[Fact]
public void Test1()
{
    // Arrange
    var expected = new[]
    {
        new {F1 = 1, F2 = "1" },
        new {F1 = 2, F2 = "2" },
    };

    // Act
    var actual = new[]
    {
        new {F1 = 1, F2 = "1", F3 = true },
        new {F1 = 2, F2 = "2", F3 = true },
        new {F1 = 3, F2 = "3", F3 = true },
    };

    // Assert
    actual
        .Should()
        .LookingForFluentAssertionsExpression( //<-- I'm looking for this part
            expected, 
            options => options.SomeOptions(),
            because: "expected is a 'subset' of actual" 
        );
}

I have tried unsuccessfully with Object graph comparison:

    // Assert
    actual
        .Should()
        .BeEquivalentTo(expected, o => o.ExcludingMissingMembers());

Expected actual to be a collection with 2 item(s), but {{ F1 = 1, F2 = 1, F3 = True }, { F1 = 2, F2 = 2, F3 = True }, { F1 = 3, F2 = 3, F3 = True }}"

"contains 1 item(s) more than"

"{{ F1 = 1, F2 = 1 }, { F1 = 2, F2 = 2 }}.

Obviously, I can do:

    // Assert
    actual
        .Where(a => expected.Any(e=>e.F1 == a.F1 && e.F2 == a.F2))
        .Should()
        .BeEquivalentTo(expected, o => o.ExcludingMissingMembers());

but looks a bit dirty.

Another option is:

    // Assert
    expected
        .ToList()
        .ForEach(expectedItem =>
            actual
                .Should()
                .ContainEquivalentOf(
                    expectation: expectedItem, 
                    config: o => o.ExcludingMissingMembers())
        );

    // Or the same without Linq: 
    //
    //foreach (var expectedItem in expected)
    //{
    //    actual
    //        .Should()
    //        .ContainEquivalentOf(
    //            expectation: expectedItem,
    //            config: o => o.ExcludingMissingMembers());
    //}

but is not readable at all.


Solution

  • You can use two calls of ContainEquivalentOf where you pass an item from the expected collection.

    e.g.

    using (new AssertionScope())
    {
      actual.Should().ContainEquivalentOf(expected[0]);
      actual.Should().ContainEquivalentOf(expected[1]);
    }
    

    And you don't need ExcludingMissingMembers. FA will only expect the properties you defined on your expectation.