Сравнение свойств вложенных объектов с помощью SemanticComparison

Я создаю модульный тест, который должен сравнить два объекта одного типа для каждого элемента. Я решил использовать библиотеку SemanticComparison для решения этой задачи без написания специального кода для сравнения. Это работает очень хорошо при сравнении плоских объектов, возникают проблемы, когда объект содержит вложенный объект, который также необходимо сравнивать по элементам.

public class Outer
{
    public string Name { get; set; }
    public Inner Inner { get; set; }
}

public class Inner
{
    public string Name { get; set; }
    public string Value { get; set; }
}

public class Service
{
    public Outer Method()
    {
        return new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        };
    }
}

Это не будет работать, потому что внутренний объект сравнивается по ссылке, а не по элементам:

    [Test]
    public void SimpleTest1()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Чтобы это работало, мне нужно было создать прокси для вложенного объекта, чтобы он переопределял реализацию по умолчанию.

    [Test]
    public void SimpleTest2()
    {

        // setup
        var expectedLikeness = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value1"
            }.AsSource().OfLikeness<Inner>().CreateProxy()
        }.AsSource().OfLikeness<Outer>();

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Хорошо, это работает правильно, но представьте, что после некоторого рефакторинга сервисного кода мы вводим ошибку, из-за которой свойство value класса Inner отличается от ожидаемого значения. Крутая особенность SemanticComparison заключается в том, что он может регистрировать имя члена, вызывающего неравенство. Но в этом случае он будет возвращать только "Inner" как несоответствие, а не имя конкретного свойства в классе Inner.

Я что-то пропустил? Можно ли настроить его так, чтобы он мог возвращать фактическое несоответствие члена.

Это, очевидно, не проблема для простых структур данных, как в этом примере, но это может быть неудобно для тестирования реального кода.

1 ответ

Решение

Поскольку никто не ответил, я предоставлю свой ответ.

Таким образом, кажется, что вы не можете сделать это OOTB, если вы не пишете дополнительный код. Я обернул код в набор методов расширения. Эти методы позволяют указать, какие внутренние свойства / свойства коллекции следует сравнивать, используя внутреннее сходство, а не по ссылке. Вам не нужно создавать какие-либо прокси вручную, все обрабатывается внутри этих расширений. И результаты всех внутренних сравнений записываются в журнал, так что вы можете точно увидеть, какой член имеет недопустимое значение.

Вот тест из вопроса с использованием метода расширения "WithInnerLikeness".

    [Test]
    public void ServiceTest3()
    {
        // setup
        var expected = new Outer()
        {
            Name = "outerName",
            Inner = new Inner()
            {
                Name = "innerName",
                Value = "value2"
            }
        };

        var expectedLikeness = expected.AsSource().OfLikeness<Outer>()
            .WithInnerLikeness(d => d.Inner, s => s.Inner)
            ;

        var sut = new Service();
        // exercise sut
        var actual = sut.Method();
        // verify
        expectedLikeness.ShouldEqual(actual);
    }

Вы можете видеть, что свойства значений внутренних объектов не совпадают, поэтому проверка должна завершиться неудачей. И это терпит неудачу со следующими сообщениями в выводе:

Comparing inner properties using likeness. Source: s => s.Inner Destination: d => d.Inner.
The source and destination values are not equal. Details: The provided value ClassLibrary1.Inner did not match the expected value ClassLibrary1.Inner. The following members did not match:
- Value.

Ploeh.SemanticComparison.LikenessException : The provided value ClassLibrary1.Outer did not match the expected value ClassLibrary1.Outer. The following members did not match:
- Inner.

Вы можете найти исходный код и другие примеры на github.

https://github.com/jmansar/SemanticComparisonExtensions

Жаль, что он не поддерживается из коробки.

В качестве альтернативы вы можете попробовать https://fluentassertions.com/, см. Сравнение графов объектов.

actual.Should().BeEquivalentTo(expected);

Существует большая гибкость в отношении сравнения, исключения членов и т. Д., А свойства вложенных объектов поддерживаются из коробки.

Надеюсь это поможет!

Другие вопросы по тегам