4

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?

Anton Georgiev
  • 610
  • 6
  • 14

1 Answers1

10

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.

Jonas Nyrup
  • 2,376
  • 18
  • 25
  • 1
    DifferentObjectsEquivalencyStep should be added to fluentassertions, as extension methods! – Michal Ciechan Mar 01 '18 at 17:50
  • 2
    @MichalCiechan Feel free to open an issue about on the [issue tracker](https://github.com/fluentassertions/fluentassertions/issues). I'm currently fiddling with another approach where you'll be able to write `.Using(ctx => ctx.Subject.Should().Be(ctx.Expectation.ToString())).When(info => info.SelectedMemberPath.EndsWith("Id")))`. That should be less fragile and more expressive. – Jonas Nyrup Mar 01 '18 at 18:23