Как в FluentAssertions сравнить два разных класса с совпадениями по полям?

Допустим есть два не всязанных наследованием класса. У них есть несколько совподающих полей (в примере ниже это поля field_1 и field_2)

class A
{
    int field_1;
    int field_2;

    int field_3;
}

class B
{
    int field_1;
    int field_2;

    int field_4;
} 

A a = new A {field_1 = 1, field_2 = 2, field_3 = 3}
B b = new B {field_1 = 1, field_2 = 2, field_4 = 4}

Можно ли написать нечто подобное a.Should().BeEquivalentTo(b); и получить положительный результат?


Ответы (1 шт):

Автор решения: Alexander Petrov

Можно перегрузить метод Equals. В паре с ним всегда следует перегружать метод GetHashCode. Они были любезно сгенерированы Студией автоматически, после чего я подправил метод Equals, чтобы происходило сравнение не только с объектом своего типа, но и другого.

public class A
{
    public int field_1;
    public int field_2;

    public int field_3;

    public override bool Equals(object obj)
    {
        if (obj is A a)
        {
            return field_1 == a.field_1
                && field_2 == a.field_2
                && field_3 == a.field_3;
        }
        else if (obj is B b)
        {
            return field_1 == b.field_1
                && field_2 == b.field_2;
        }
        return false;
    }

    public override int GetHashCode()
    {
        int hashCode = -1805700735;
        hashCode = hashCode * -1521134295 + field_1.GetHashCode();
        hashCode = hashCode * -1521134295 + field_2.GetHashCode();
        return hashCode;
    }
}

public class B
{
    public int field_1;
    public int field_2;

    public int field_4;

    public override bool Equals(object obj)
    {
        if (obj is B b)
        {
            return field_1 == b.field_1
                && field_2 == b.field_2
                && field_4 == b.field_4;
        }
        else if (obj is A a)
        {
            return field_1 == a.field_1
                && field_2 == a.field_2;
        }
        return false;
    }

    public override int GetHashCode()
    {
        int hashCode = -1805700735;
        hashCode = hashCode * -1521134295 + field_1.GetHashCode();
        hashCode = hashCode * -1521134295 + field_2.GetHashCode();
        return hashCode;
    }
}

Этот способ полезен не только для модульного тестирования, но и для сравнения объектов в реальном коде.


Если сравниваемые типы нельзя/нежелательно менять, то можно обойтись возможностями FluentAsserions:

a.Should().BeEquivalentTo(b, options => options.ExcludingMissingMembers());

По умолчанию BeEquivalentTo сравнивает все члены объектов. Но можно исключить из сравнения отсутствующие.

Или, наоборот, можно указать только те свойства/поля, которые должны участвовать в сравнении:

a.Should().BeEquivalentTo(b, options => options
    .Including(x => x.field_1).Including(x => x.field_2));

Документация: Object graph comparison

→ Ссылка