Tim Calladene
Tim Calladene

Reputation: 126

How to check equivalence using Fluent Assertion Should().BeEquivalentTo() when using derived classes

I'm having problems trying to get Should().BeEquivalentTo() to work with types that derive from a base class and implement a collection interface:

public class Entity
{
    public string Id {get; set;}
    public string Name {get; set;}
}

public class Derived : Entity, ICollection<Entity>
{
    private List<Entity> m_Children = new List<Entity>();

    public string Description { get; set; }

    public int Count => ((ICollection<Entity>)m_Children).Count;

    public bool IsReadOnly => ((ICollection<Entity>)m_Children).IsReadOnly;

    public void Add(Entity item)
    {
        ((ICollection<Entity>)m_Children).Add(item);
    }

    public void Clear()
    {
        ((ICollection<Entity>)m_Children).Clear();
    }

    public bool Contains(Entity item)
    {
        return ((ICollection<Entity>)m_Children).Contains(item);
    }

    public void CopyTo(Entity[] array, int arrayIndex)
    {
        ((ICollection<Entity>)m_Children).CopyTo(array, arrayIndex);
    }

    public IEnumerator<Entity> GetEnumerator()
    {
        return ((ICollection<Entity>)m_Children).GetEnumerator();
    }

    public bool Remove(Entity item)
    {
        return ((ICollection<Entity>)m_Children).Remove(item);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((ICollection<Entity>)m_Children).GetEnumerator();
    }
}

The Test

[TestMethod]
public void EquivalenceTest()
{
    var expected = new Derived
    {
        Id = "123",
        Name = "abc",
        Description = "def"
    };
    var actual = new Derived
    {
        Id = "121",
        Name = "xyz",
        Description = "def"
    };    

    actual.Should().BeEquivalentTo(expected);   // This succeeds, but should fail
}

The call to BeEquivalentTo seems to be ignoring the properties that are defined in the object, and only treating the object as a collection.

How can I get the framework to check the properties and the contents of the collection?

Edit It seems like this is a known issue

Does anyone know of a workaround?

Upvotes: 2

Views: 1297

Answers (2)

Master DJon
Master DJon

Reputation: 1965

I know it's a bit old and maybe it was not existing at that time, but this is doing the trick for me and shall have been for you.

actual.Should().BeEquivalentTo(expected, opt => opt.RespectingRuntimeTypes());

Upvotes: 0

Jonas Nyrup
Jonas Nyrup

Reputation: 2586

It's a known issue when comparing classes that implements IEnumerable and have extra properties to be compared.

Here's a way to hack the comparison.

public class Entity : IEnumerable<int>
{
    private int[] ints = new[] { 1 };

    public int Id { get; set; }

    public string Name { get; set; }

    public IEnumerator<int> GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
}

[TestMethod]
public void EquivalenceTest()
{
    var expected = new Entity
    {
        Id = 1,
        Name = "abc",
    };

    var actual = new Entity
    {
        Id = 1,
        Name = "abc",
    };

    actual.Should().BeEquivalentTo(expected, opt => opt
        .Using<Entity>(e =>
            e.Subject.Should().Match<Entity>(f => f.Name == e.Expectation.Name)
            .And.Subject.Should().Match<Entity>(f => f.Id == e.Expectation.Id)
                .And.Subject.Should().BeEquivalentTo(e.Expectation)
        )
        .WhenTypeIs<Entity>());
}

Upvotes: 1

Related Questions