In our project we have classes inherited from collections. These classes have own properties and we should compare their instances only by specified properties and ignore data in collections. But the Fluent Assertion's object comparer always compares objects as collections first.
Is this a bug? If not then how to compare similar objects only by specified properties?
Code to test the specified problem.
using System;
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
namespace FluentAssertionsTests
{
[TestFixture]
public class Tests
{
public class TestCollection : List<int>
{
public TestCollection()
{
Uid = Guid.NewGuid();
}
public int CollectionId { get; set; }
public Guid Uid { get; set; }
}
[Test]
public void DifferentCollectionsObjectGraphComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
actual.Add(1);
var expected = new TestCollection {CollectionId = 1};
expected.Add(2);
// this test failed with "Expected item[0] to be 2, but found 1."
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.CollectionId));
}
[Test]
public void ObjectGraphComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
var expected = new TestCollection {CollectionId = 1};
// this test success
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.CollectionId));
actual.Uid.Should().NotBe(expected.Uid);
// this test success but should be failed because objects has a different Uid
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.Uid));
// this test success but should be failed because objects has a different Uid
actual.ShouldBeEquivalentTo(expected);
}
[Test]
public void DifferentCollectionsPropertyComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
actual.Add(1);
var expected = new TestCollection {CollectionId = 1};
expected.Add(2);
// this test failed with "Expected item[0] to be 2, but found 1."
actual.ShouldHave().Properties(p => p.CollectionId).EqualTo(expected);
}
[Test]
public void ObjectPropertyComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
var expected = new TestCollection {CollectionId = 1};
// this test success
actual.ShouldHave().Properties(p => p.CollectionId).EqualTo(expected);
actual.Uid.Should().NotBe(expected.Uid);
// this test success but should be failed because objects has a different Uid
actual.ShouldHave().Properties(p => p.Uid).EqualTo(expected);
// this test success but should be failed because objects has a different Uid
actual.ShouldHave().AllProperties().EqualTo(expected);
}
}
}
Comments: That's because the object implements IEnumerable. If you want to force FA to use an alternative comparison, you need to override that behavior using the Using<T>() method on the options object. See specification When_an_assertion_is_overridden_for_a_predicate_it_should_use_the_provided_action() in EquivalencySpecs.cs for an example.
Is this a bug? If not then how to compare similar objects only by specified properties?
Code to test the specified problem.
using System;
using System.Collections.Generic;
using FluentAssertions;
using NUnit.Framework;
namespace FluentAssertionsTests
{
[TestFixture]
public class Tests
{
public class TestCollection : List<int>
{
public TestCollection()
{
Uid = Guid.NewGuid();
}
public int CollectionId { get; set; }
public Guid Uid { get; set; }
}
[Test]
public void DifferentCollectionsObjectGraphComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
actual.Add(1);
var expected = new TestCollection {CollectionId = 1};
expected.Add(2);
// this test failed with "Expected item[0] to be 2, but found 1."
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.CollectionId));
}
[Test]
public void ObjectGraphComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
var expected = new TestCollection {CollectionId = 1};
// this test success
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.CollectionId));
actual.Uid.Should().NotBe(expected.Uid);
// this test success but should be failed because objects has a different Uid
actual.ShouldBeEquivalentTo(expected, options => options.Including(p => p.Uid));
// this test success but should be failed because objects has a different Uid
actual.ShouldBeEquivalentTo(expected);
}
[Test]
public void DifferentCollectionsPropertyComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
actual.Add(1);
var expected = new TestCollection {CollectionId = 1};
expected.Add(2);
// this test failed with "Expected item[0] to be 2, but found 1."
actual.ShouldHave().Properties(p => p.CollectionId).EqualTo(expected);
}
[Test]
public void ObjectPropertyComparisonTest()
{
var actual = new TestCollection {CollectionId = 1};
var expected = new TestCollection {CollectionId = 1};
// this test success
actual.ShouldHave().Properties(p => p.CollectionId).EqualTo(expected);
actual.Uid.Should().NotBe(expected.Uid);
// this test success but should be failed because objects has a different Uid
actual.ShouldHave().Properties(p => p.Uid).EqualTo(expected);
// this test success but should be failed because objects has a different Uid
actual.ShouldHave().AllProperties().EqualTo(expected);
}
}
}
Comments: That's because the object implements IEnumerable. If you want to force FA to use an alternative comparison, you need to override that behavior using the Using<T>() method on the options object. See specification When_an_assertion_is_overridden_for_a_predicate_it_should_use_the_provided_action() in EquivalencySpecs.cs for an example.