Home > OS >  FluentAssertions: Test if an Enumerable contains "subset" of itself
FluentAssertions: Test if an Enumerable contains "subset" of itself

Time:01-31

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.

CodePudding user response:

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

CodePudding user response:

The HashSet<T> has the methods .IsSuperset() and .IsSubset() to make the desired checks:

// Arrange
var expected = new[]
{
    new { F1 = 1, F2 = "1", F3 = true },
    new { F1 = 2, F2 = "2", F3 = true },
};

// 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
var actualHashSet = actual.ToHashSet();
var isSuperset = actualHashSet.IsSupersetOf(expected);

isSuperset.ShouldBeTrue();

var expectedHashSet = expected.ToHashSet();
var isSubset = expectedHashSet.IsSubsetOf(actual);

isSubset.ShouldBeTrue();

CodePudding user response:

At the end, I coded it using a ClassData. I don't know if this is the best solution, I post it here with the other answers. Feel free to criticize this answer. We are here to learn.

public class CalculatorTestData : IEnumerable<object[]>
{
    public IEnumerator<object[]> GetEnumerator()
    {
        yield return new object[] { new { F1 = 1, F2 = "1" }, "reason 1" };
        yield return new object[] { new { F1 = 2, F2 = "2" }, "reason 2" };
    }

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}

[Theory]
[ClassData(typeof(CalculatorTestData))]
public void Test2(object expected, string because)
{
    // Arrange

    // 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()
        .ContainEquivalentOf(
            expectation: expected,
            config: o => o.ExcludingMissingMembers(),
            because: because);
}
  • Related