Anton Georgiev
Anton Georgiev

Reputation: 620

FluentAssertions - Should().BeEquivalentTo() when properties are of different type

How to compare objects that have a property with the same name but different type?

public class A
{
    public Guid Id { get; set; }
}

public class B
{
    public string Id { get; set; }
}

public static B Map(A a){
    return new B { Id = a.Id.ToString() };
}

Version 1:

void Main()
{
    A a = new A { Id = Guid.NewGuid() };
    B b = Map(a);

    b.Should().BeEquivalentTo(a);
}

This produces the following error:

AssertionFailedException: Expected member Id to be {ff73e7c7-21f0-4f45-85fa-f26cd1ecafd0}, but found "{ff73e7c7-21f0-4f45-85fa-f26cd1ecafd0}".

The documentation suggests that custom property assertion rules could be possible using the Equivalence Comparison Behavior

Version 2:

void Main()
{
    A a = new A { Id = Guid.NewGuid() };
    B b = Map(a);

    b.Should().BeEquivalentTo(a, 
        options => options
            .Using<Guid>(ctx => ctx.Subject.Should().Be(ctx.Expectation))
            .WhenTypeIs<Guid>());
}

but it produces run-time exception if the properties are not of the same type.

AssertionFailedException: Expected member Id from subject to be a System.Guid, but found a System.String.

Any ideas?

Upvotes: 5

Views: 10518

Answers (1)

Jonas Nyrup
Jonas Nyrup

Reputation: 2586

Here are two approaches to compare objects with identically named members of different type.

The first way is to specify equivalency between members named Id

A expected = new A { Id = Guid.NewGuid() };
B actual = Map(expected);

actual.Should().BeEquivalentTo(expected,
    options => options
    .Using<object>(ctx => ctx.Subject.Should().Be(ctx.Expectation.ToString()))
    .When(info => info.SelectedMemberPath.EndsWith("Id")));

The second approach uses the DifferentObjectsEquivalencyStep from https://stackoverflow.com/a/47947052/1087627 and your own Map function. It then converts instances of A into B, which are now easy to compare.

AssertionOptions.AssertEquivalencyUsing(c => 
    c.Using(new DifferentObjectsEquivalencyStep<A, B>(Map)));

A expected = new A { Id = Guid.NewGuid() };
B actual = Map(expected);

actual.Should().BeEquivalentTo(expected);

There is an open issue about it.

Upvotes: 11

Related Questions