Reputation: 620
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
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